iOS边练边学--NSURLSessionDataTask实现文件真正的断点续传
2016-05-04 19:27
507 查看
实现重点:
NSURLSessionDataTask要设置请求头,从路径中获取文件已经下载的长度(文件没有下载过的话,长度为0)。通过这个长度设置请求的Range
如图:
接收到请求的时候key:文件名(经过MD5加密过的URL,Url保证了文件名的唯一) Value:该文件已经下载过的长度。保存成plist文件,方便对下载文件的判断
利用NSOutUpStream写文件
在任务完成的代理方法里面,NSOutUpStream关闭并且清空,对应的task清空,对应的session清空
代码如下:
NSURLSessionDataTask要设置请求头,从路径中获取文件已经下载的长度(文件没有下载过的话,长度为0)。通过这个长度设置请求的Range
如图:
接收到请求的时候key:文件名(经过MD5加密过的URL,Url保证了文件名的唯一) Value:该文件已经下载过的长度。保存成plist文件,方便对下载文件的判断
利用NSOutUpStream写文件
在任务完成的代理方法里面,NSOutUpStream关闭并且清空,对应的task清空,对应的session清空
代码如下:
#import "ViewController.h" #import "NSString+Hash.h" // 下载文件的URL #define ChaosFileURL @"http://120.25.226.186:32812/resources/videos/minion_01.mp4" // 根据文件唯一的URL MD5值 作为文件名 #define ChaosFileName ChaosFileURL.md5String // 用来存储文件总长度的plist文件 key:文件名的MD5值 value:文件总长度 #define ChaosDownloadFilesPlist [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"downloadFiles.plist"] // 下载文件的全路径 #define ChaosFileFullPath [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:ChaosFileName] // 已经下载的文件长度 #define ChaosDownloadLength [[[NSFileManager defaultManager] attributesOfItemAtPath:ChaosFileFullPath error:nil][@"NSFileSize"] integerValue] @interface ViewController () <NSURLSessionDataDelegate> /** stream */ @property(nonatomic,strong) NSOutputStream *stream; /** session */ @property(nonatomic,strong) NSURLSession *session; /** task */ @property(nonatomic,strong) NSURLSessionDataTask *task; /** totalLength */ @property(nonatomic,assign) NSInteger totalLength; /** downloadLength */ @property(nonatomic,assign) NSInteger downloadLength; @end @implementation ViewController - (NSURLSession *)session { if (_session == nil) { _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]]; } return _session; } - (NSURLSessionDataTask *)task { if (_task == nil) { // 获得文件总长度 NSInteger totalLength = [[NSDictionary dictionaryWithContentsOfFile:ChaosDownloadFilesPlist][ChaosFileName] integerValue]; // 请求同一个文件,判断下载文件长度;如果没下载过此文件,totalLength = 0 if (totalLength && ChaosDownloadLength == totalLength) { NSLog(@"文件已经下载过."); return nil; } NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:ChaosFileURL]]; // 设置请求头 -- range 这次从哪里开始请求数据 格式:bytes=***-***(从指定开始到指定结束) 或者:bytes=***-(从指定位置到结束) NSString *range = [NSString stringWithFormat:@"bytes=%zd-",ChaosDownloadLength]; [request setValue:range forHTTPHeaderField:@"Range"]; _task = [self.session dataTaskWithRequest:request]; } return _task; } // 开始 - (IBAction)startClick:(id)sender { [self.task resume]; } // 暂停 - (IBAction)pauseClick:(id)sender { [self.task suspend]; } - (void)viewDidLoad { [super viewDidLoad]; } #pragma mark - <NSURLSessionDataDelegate> /** * 接收到响应的时候调用 */ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { // 调用blcok,才能接受到数据 completionHandler(NSURLSessionResponseAllow); // 初始化stream self.stream = [NSOutputStream outputStreamToFileAtPath:ChaosFileFullPath append:YES]; [self.stream open]; // 获取文件总长度 self.totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + ChaosDownloadLength; // 接收到服务器响应的时候存储文件的总长度到plist,实现多文件下载,先取出字典,给字典赋值最后写入。 // 错误做法:直接写入文件,会用这次写入的信息覆盖原来所有的信息 NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:ChaosDownloadFilesPlist]; // 字典可能为空 if (dict == nil) dict = [NSMutableDictionary dictionary]; // 写入文件 dict[ChaosFileName] = @(self.totalLength); [dict writeToFile:ChaosDownloadFilesPlist atomically:YES]; } /** * 接收到服务器发来的数据的时候调用 -- 有可能调用多次 */ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { // 写入数据 [self.stream write:[data bytes] maxLength:data.length]; // 获取已经下载的长度 self.downloadLength = ChaosDownloadLength; // 计算进度 NSLog(@"%f",1.0 * self.downloadLength / self.totalLength); } /** * 任务完成的时候调用 */ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { NSLog(@"----finish"); [self.stream close]; self.stream = nil; // 一个任务对应一个文件,用完清空 self.task = nil; } @end
相关文章推荐
- iOS tableView 一共0行时候去掉分割线 和 去掉多余分割线
- iOS开发系列--通知与消息机制
- iOS开发使用半透明模糊效果方法整理
- iOS通知NSNotificationCenter的使用
- iOS的内存管理
- iOS自定义控制中心音乐播放 锁屏界面背景图片
- IOS开发】@selector 调用方法,传递多参数。
- iOS NSJSONSerialization使用
- iOS - 设置Iconfont文字“图标”
- ld: library not found for -lPods 解决方法
- IOS Socket 02-Socket基础知识
- iOS_学习代码混淆
- iOS 每次登录进入首页
- 关于ios8以上原生推送不执行返回deviceToken方法的解决
- iOS学习札记之GET和POST请求
- IOS MenuController的部分操作
- IOS 生成本地验证码
- iOS安装CocoaPods
- iOS开发中@interface 和 @implementation区别, @property 和@synthesize区别
- iOS线程初探(四) GCD 和 NSOperation 小结