zoukankan      html  css  js  c++  java
  • iOS边练边学--NSURLSessionDataTask实现文件真正的断点续传

    实现重点:

    • NSURLSessionDataTask要设置请求头,从路径中获取文件已经下载的长度(文件没有下载过的话,长度为0)。通过这个长度设置请求的Range

    如图:

    • 接收到请求的时候key:文件名(经过MD5加密过的URL,Url保证了文件名的唯一) Value:该文件已经下载过的长度。保存成plist文件,方便对下载文件的判断
    • 利用NSOutUpStream写文件
    • 在任务完成的代理方法里面,NSOutUpStream关闭并且清空,对应的task清空,对应的session清空

    代码如下:

      1 #import "ViewController.h"
      2 #import "NSString+Hash.h"
      3 
      4 // 下载文件的URL
      5 #define ChaosFileURL @"http://120.25.226.186:32812/resources/videos/minion_01.mp4"
      6 
      7 // 根据文件唯一的URL MD5值 作为文件名
      8 #define ChaosFileName ChaosFileURL.md5String
      9 
     10 // 用来存储文件总长度的plist文件 key:文件名的MD5值 value:文件总长度
     11 #define ChaosDownloadFilesPlist [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"downloadFiles.plist"]
     12 
     13 // 下载文件的全路径
     14 #define ChaosFileFullPath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:ChaosFileName]
     15 
     16 // 已经下载的文件长度
     17 #define ChaosDownloadLength [[[NSFileManager defaultManager] attributesOfItemAtPath:ChaosFileFullPath error:nil][@"NSFileSize"] integerValue]
     18 
     19 @interface ViewController () <NSURLSessionDataDelegate>
     20 
     21 /** stream */
     22 @property(nonatomic,strong) NSOutputStream *stream;
     23 
     24 /** session */
     25 @property(nonatomic,strong) NSURLSession *session;
     26 
     27 /** task */
     28 @property(nonatomic,strong) NSURLSessionDataTask *task;
     29 
     30 /** totalLength */
     31 @property(nonatomic,assign) NSInteger totalLength;
     32 
     33 /** downloadLength */
     34 @property(nonatomic,assign) NSInteger downloadLength;
     35 
     36 @end
     37 
     38 @implementation ViewController
     39 
     40 - (NSURLSession *)session
     41 {
     42     if (_session == nil) {
     43         
     44         _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
     45     }
     46     
     47     return _session;
     48 }
     49 
     50 - (NSURLSessionDataTask *)task
     51 {
     52     if (_task == nil) {
     53         
     54         // 获得文件总长度
     55         NSInteger totalLength = [[NSDictionary dictionaryWithContentsOfFile:ChaosDownloadFilesPlist][ChaosFileName] integerValue];
     56         // 请求同一个文件,判断下载文件长度;如果没下载过此文件,totalLength = 0
     57         if (totalLength && ChaosDownloadLength == totalLength) {
     58             NSLog(@"文件已经下载过.");
     59             return nil;
     60         }
     61         
     62         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:ChaosFileURL]];
     63         
     64         // 设置请求头 -- range 这次从哪里开始请求数据 格式:bytes=***-***(从指定开始到指定结束)  或者:bytes=***-(从指定位置到结束)
     65         NSString *range = [NSString stringWithFormat:@"bytes=%zd-",ChaosDownloadLength];
     66         
     67         [request setValue:range forHTTPHeaderField:@"Range"];
     68         
     69         _task = [self.session dataTaskWithRequest:request];
     70         
     71     }
     72     return _task;
     73 }
     74 
     75 // 开始
     76 - (IBAction)startClick:(id)sender {
     77     
     78     [self.task resume];
     79 }
     80 // 暂停
     81 - (IBAction)pauseClick:(id)sender {
     82     
     83     [self.task suspend];
     84 }
     85 
     86 - (void)viewDidLoad {
     87     [super viewDidLoad];
     88 }
     89 
     90 #pragma mark - <NSURLSessionDataDelegate>
     91 /** 
     92  * 接收到响应的时候调用
     93  */
     94 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
     95 {
     96     // 调用blcok,才能接受到数据
     97     completionHandler(NSURLSessionResponseAllow);
     98     // 初始化stream
     99     self.stream = [NSOutputStream outputStreamToFileAtPath:ChaosFileFullPath append:YES];
    100     [self.stream open];
    101     
    102     // 获取文件总长度
    103     self.totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + ChaosDownloadLength;
    104     
    105     // 接收到服务器响应的时候存储文件的总长度到plist,实现多文件下载,先取出字典,给字典赋值最后写入。
    106     // 错误做法:直接写入文件,会用这次写入的信息覆盖原来所有的信息
    107     NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:ChaosDownloadFilesPlist];
    108     // 字典可能为空
    109     if (dict == nil) dict = [NSMutableDictionary dictionary];
    110     // 写入文件
    111     dict[ChaosFileName] = @(self.totalLength);
    112     [dict writeToFile:ChaosDownloadFilesPlist atomically:YES];
    113 }
    114 
    115 /**
    116  * 接收到服务器发来的数据的时候调用 -- 有可能调用多次
    117  */
    118 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
    119 {
    120     // 写入数据
    121     [self.stream write:[data bytes] maxLength:data.length];
    122     // 获取已经下载的长度
    123     self.downloadLength = ChaosDownloadLength;
    124     // 计算进度
    125     NSLog(@"%f",1.0 * self.downloadLength / self.totalLength);
    126 }
    127 
    128 /**
    129  * 任务完成的时候调用
    130  */
    131 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
    132 {
    133     NSLog(@"----finish");
    134     [self.stream close];
    135     self.stream = nil;
    136     
    137     // 一个任务对应一个文件,用完清空
    138     self.task = nil;
    139 }
    140 @end
  • 相关阅读:
    木马后门入侵与RKHunter,ClamAV检测工具
    Jenkins环境搭建
    Mha-Atlas-MySQL高可用
    JAVA企业级应用服务器之TOMCAT实战
    Keepalived高可用集群
    scp ssh-key连接原理
    jumpserver跳板机搭建
    DNS域名解析服务器
    DHCP服务
    Keepalived高可用集群
  • 原文地址:https://www.cnblogs.com/gchlcc/p/5459546.html
Copyright © 2011-2022 走看看