AFNetworking 文件断点下载详细解读

看过很多人写的文件断点下载的项目,包括GitHub上面的,但是有个共同特点不满足需求,或者有点过度封装,过度封装那是有点蛋疼的。。所以哥们我决定来一发。当然,我也不是省油的灯,发表我的观点之前先来讽刺下一段脑残的号称断点下载的代码。。。。。。 你可以在自己的Xcode上搞一搞,但是别忘了导入AFNetworking 3.0的包;先来欣赏一把。。。 


断点上传参考 http://blog.csdn.net/chmod_r_755/article/details/73741912


AFNetworking 文件断点下载详细解读_第1张图片



完全没有理解神马叫断点下载,瞎扯犊子

其一:上面的方法较适合小文件下载,比如下载个图片音频什么的

其二:断点下载,断点下载的意思是,我把APP关掉,下次进来可以继续上次我的下载,安装上面的方法,尼玛APP一关一个几十兆的文件还他妈能接着下载吗?  





下面来说下我的方法和思路

文件其实归根结底是一种二进制流;文件下载可以这样理解,把一个很大很大的文件分割成一小块一小块,从服务端经网络一块一块的流向客户端,说的比较抽象,来张图

AFNetworking 文件断点下载详细解读_第2张图片


假设服务器上有个文件File 大小是 1200kb , 我们可以把它理解成若干个块(这里我为演示把它分成12个块)每个块是100kb(理想情况仅为了演示),下载文件肯定是从第一个块到第十二块这样下载,才能组合成有一个完整的文件

其实NSURLRequest这个类给我们提供了一个方法

- (void)setValue:(nullableNSString *)value forHTTPHeaderField:(NSString *)field;


那么我们怎么使用了 ?断点下载中我们通常这样用

 [request setValue:@"bytes=120-forHTTPHeaderField:@"Range"];

bytes=120-  这又是个神马鬼了 ?

其实这个鬼还蛮给力的 。。。 就是我们上面提到的块,

如果不使用这个方法默认从 0 下载到最后一个字节

我们有以下几个格式

1: bytes=120-            表示从120字节以后开始下载(包括120字节,这不重要其实)

2: bytes=120-1234        表示下载120-1234字节的数据(包括120字节,包括1234)

3: bytes=0-120           表示从头开始下载到120字节处

4: bytes=-120            表示下载最后120字节

5: bytes=120-1234,1567-2456        表示下载120-1234字节的数据和 1567-2456



重点来说下这个方法 ,


 task = [managerdataTaskWithRequest:request uploadProgress:NULLdownloadProgress:^(NSProgress *_Nonnull downloadProgress) {

    

        fileTotalSize = downloadProgress.totalUnitCount;

        

    } completionHandler:^(NSURLResponse *_Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {

         NSLog(@"%ld ======     ",fileTotalSize);

    }];



这个方法是下载的时候获取文件大小的方法。如果你是从 0 字节开始下载的话,downloadProgress.totalUnitCount就是文件的总大小 ,如果你设置了 bytes=120-  那么 这个时候downloadProgress.totalUnitCount就是文件的总大小去掉120 ,这个很重要

好了 贴代码。。。。。  你首先需要导入AFNetworking , 然后在模拟器上运行下,因为模拟器上可以打印出地址



#import "ViewController.h"
#import "AFNetworking.h"



#define URL @"http://7fvipe.com1.z0.glb.clouddn.com/322196.jpg"

#define FILEPATH [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"download/org"]
#define FILEPATHName [FILEPATH stringByAppendingPathComponent:@"test8.png"]

@interface ViewController (){
    
    NSURLSessionDataTask *task;
    
    NSFileHandle *fileHandle;
    UILabel *showLabel;
    

    __block  NSInteger  fileCompleteSize ;
    __block  NSUInteger fileTotalSize ;

}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSLog(@"%@",FILEPATH);
    
    
    fileCompleteSize = 0;
    fileTotalSize = 0;
    
    
    UIButton *button1 = [[UIButton alloc ] init];
    button1.frame = CGRectMake(10, 40, 80, 100);
    [button1 setTitle:@"开始下载" forState:UIControlStateNormal];
    [button1 addTarget:self action:@selector(button1) forControlEvents:UIControlEventTouchUpInside];
    button1.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:button1];
    
    
    button1 = [[UIButton alloc ] init];
    button1.frame = CGRectMake(110, 40, 80, 100);
    [button1 setTitle:@"暂停下载" forState:UIControlStateNormal];
    [button1 addTarget:self action:@selector(button2) forControlEvents:UIControlEventTouchUpInside];
    button1.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:button1];
    
    
    
    button1 = [[UIButton alloc ] init];
    button1.frame = CGRectMake(210, 40, 80, 100);
    [button1 setTitle:@"继续下载" forState:UIControlStateNormal];
    [button1 addTarget:self action:@selector(button3) forControlEvents:UIControlEventTouchUpInside];
    button1.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:button1];
    
    
    
    showLabel = [[UILabel alloc] init];
    showLabel.frame = CGRectMake(0, 200, self.view.frame.size.width, 40);
    showLabel.textAlignment = NSTextAlignmentCenter;
    showLabel.textColor = [UIColor redColor];
    [self.view addSubview:showLabel];
    
    
 
     NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:URL]];
    
    
    task = [manager dataTaskWithRequest:request uploadProgress:NULL downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
    
        fileTotalSize = downloadProgress.totalUnitCount;
        
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
         NSLog(@"%ld ======     ", fileTotalSize);
    }];

    
    [manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSURLResponse * _Nonnull response) {
        
        NSFileManager *fma = [NSFileManager defaultManager];
        
        if (![fma fileExistsAtPath:FILEPATH]) {
            // 如果没有下载文件的话,就创建一个文件。如果有下载文件的话,则不用重新创建(不然会覆盖掉之前的文件)
           
          BOOL b = [fma createDirectoryAtPath:FILEPATH withIntermediateDirectories:YES attributes:nil error:NULL];
            if (b) {
                NSLog(@"=============");
            }else{
                 NSLog(@"===###############=====");
            }
            
            
            
            if (![fma fileExistsAtPath:FILEPATHName]) {
                
                b =  [fma createFileAtPath:FILEPATHName contents:nil attributes:nil];
                
                if (b) {
                    NSLog(@"=============");
                }else{
                    NSLog(@"===###############=====");
                }
            }
          
        }
        
        fileHandle = [NSFileHandle fileHandleForWritingAtPath:FILEPATHName];
        
        
        
        return NSURLSessionResponseAllow;
    }];
    
    [manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
        
        long long l = [fileHandle seekToEndOfFile];
        [fileHandle writeData:data];
        fileCompleteSize += data.length;
        
        
        NSLog(@"%lld",l);

        
        NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];
        [mainQueue addOperationWithBlock:^{
          
            showLabel.text = [NSString stringWithFormat:@"%ld / %ld",fileCompleteSize,fileTotalSize];
        }];
        
        
    }];
    
   
    
    
    
    
   
    
   
    
    
    
    
    
}


-(void)button1{
    
     [task resume];
}

-(void)button2{
    [task suspend];
}
-(void)button3{
    
//     [task resume];
    [self contiuneAction];
}


-(void)contiuneAction{
    
    if (task) {
        task = nil;
    }
    
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:URL]];
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-", fileCompleteSize];
    [request setValue:range forHTTPHeaderField:@"Range"];
    
    
    
    
    
    task = [manager dataTaskWithRequest:request uploadProgress:NULL downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
        
        fileTotalSize = downloadProgress.totalUnitCount;
        
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        NSLog(@"%ld ======     ", fileTotalSize);
    }];
    
    
    [manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSURLResponse * _Nonnull response) {
        
        NSFileManager *fma = [NSFileManager defaultManager];
        
        BOOL b = [fma createDirectoryAtPath:FILEPATH withIntermediateDirectories:YES attributes:nil error:NULL];
        if (b) {
            NSLog(@"=============");
        }else{
            NSLog(@"===###############=====");
        }
        
        
        
        if (![fma fileExistsAtPath:FILEPATHName]) {
            
            b =  [fma createFileAtPath:FILEPATHName contents:nil attributes:nil];
            
            if (b) {
                NSLog(@"=============");
            }else{
                NSLog(@"===###############=====");
            }
        }

        
        
         fileHandle = [NSFileHandle fileHandleForWritingAtPath:FILEPATHName];
        
        return NSURLSessionResponseAllow;
    }];
    
    [manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
        
        long long l = [fileHandle seekToEndOfFile];
        [fileHandle writeData:data];
        fileCompleteSize += data.length;
        
        
        NSLog(@"%lld",l);
        
        NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];
        [mainQueue addOperationWithBlock:^{
            
            showLabel.text = [NSString stringWithFormat:@"%ld / %ld",fileCompleteSize,fileTotalSize];
        }];
        
        
    }];
    
    [task resume];
    

}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end


然后, 来张截图 。。。


AFNetworking 文件断点下载详细解读_第3张图片


[taskresume];  的意思是 继续下载, 那么我建议是 你把下载暂停,然后去WC蹲个十分钟,然后让他继续下载看行不行, 然后你就明白我为什么这么干了。 。

AFNetworking 文件断点下载详细解读_第4张图片




欧了 。。。。。 
















你可能感兴趣的:(IOS)