NSURLSessionDownloadTask支持大文件下载
本节知识点:
- 第一种方法, block 下载, 不能监听下载进度
- 第二种方法, 代理下载, 可以监听下载进度
1. 第一种方法, block 下载, 不能监听下载进度
- 1)使用 NSURLSession 和 NSURLSessionDownloadTask 可以很方便的实现文件下载操作
- 2)downloadTaskWithURL 内部默认已经实现了变下载边写入操作,所以不用开发人员担心内存问题
- 3)文件下载后默认保存在 tmp 文件目录,需要开发人员手动的剪切到合适的沙盒目录, 如果不剪切到合适的沙盒目录中, 在 tmp 目录会不定时删除数据
- 4)缺点:没有办法监控下载进度
实现步骤:
- 确定请求路径
- 创建请求对象
- 创建 session 会话对象(获取单例对象)
- 创建 DownloadTask , 是根据 session 会话对象调用
downloadTaskWithRequest: completionHandler:
方法创建downloadTaskWithURL:
方法已经实现了在下载文件数据的过程中边下载文件数据,边写入到沙盒文件的操作, 但是不能再下载完成时回调解析数据因此不用此方法downloadTaskWithRequest: completionHandler:
方法已经实现了在下载文件数据的过程中边下载文件数据,边写入到沙盒文件的操作, 可以在回调中解析数据, 并将文件从 tmp 目录转移,避免被删除
- 执行 task
- 回调解析, 转移数据
- 注意:数据是存储在 temp 文件夹中随时都有可能被删除, 因此就要有下面的步骤
- 剪切到安全的地方
缺点: 不能监听文件下载进度
相关代码
//无法监听文件的下载进度 -(void)downloadBlock { //1.确定请求路径 NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建会话对象 NSURLSession *session = [NSURLSession sharedSession]; //4.task /* 第一个参数:location 临时存储路径 第二个参数:response 响应头信息 第三个参数:error 错误信息 */ //说明:downloadTaskWithRequest方法已经实现了在下载文件数据的过程中边下载文件数据,边写入到沙盒文件的操作 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 打印文件临时存储路径, 随时会被删除, 根据路径可能已经找不到文件了, 是因为已经被删除 NSLog(@"%@",location); /* file:///Users/apple/Library/Developer/CoreSimulator/Devices/493D8296-6BCE-4646-871A-B399533590AE/data/Containers/Data/Application/322FC5D9-8B95-4E53-81E3-5A3965D377DE/tmp/CFNetworkDownload_l5MBnn.tmp */ //剪切到安全的地方 //得到caches路径 NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; // 根据响应的信息(属性)设置文件名称 NSString *fileName = response.suggestedFilename; //拼接全路径 NSString *fullPath = [caches stringByAppendingPathComponent:fileName]; //剪切文件 /* 第一个参数:要剪切的文件在哪里 NSURL 第二个参数:要剪切到什么地方 NSURL 第三个参数:错误信息 */ // [[NSFileManager defaultManager] moveItemAtPath:<#(nonnull NSString *)#> toPath:<#(nonnull NSString *)#> error:<#(NSError * _Nullable __autoreleasing * _Nullable)#>] [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil]; // 打印剪切后的文件路径 NSLog(@"%@",fullPath); }]; //5.执行task [downloadTask resume]; }
2. 第二种方法, 代理下载, 可以监听下载进度
- 1)创建NSURLSession并设置代理,通过NSURLSessionDownloadTask并以代理的方式来完成大文件的下载
- 2)常用代理方法的说明
- 3)实现断点下载相关代码
- 开始下载
- 暂停
- 取消
- 恢复
- 4)计算当前下载进度
- 5)局限性
- 如果用户点击暂停之后退出程序,那么需要把恢复下载的数据写一份到沙盒,代码复杂度大
- 如果用户在下载中途未保存恢复下载数据即退出程序,则不具备可操作性
- 实现步骤
- 确定请求路径
- 创建请求对象
- 创建会话对象 session, 类方法创建
sessionWithConfiguration:delegate:delegateQueue:
- 设置配置
- 设置代理
- 设置(代理方法的)执行队列
- 创建下载任务 downloadTask , 通过会话对象 session
- 执行任务
- 遵循代理协议, 实现代理方法
- 下载文件
- 监听下载进度
- 剪切文件到安全的地方
- 常用的代理方法
-(void)URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
- 写数据的时候调用, 可能会被调用很多次
-(void)URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:
- (取消--继续下载)恢复下载的时候回调用
-(void)URLSession:downloadTask:didFinishDownloadingToURL:
- 当下载完成的时候调用
-(void)URLSession:task:didCompleteWithError:
- 当请求结束的时候调用
相关代码
//1)创建NSURLSession并设置代理,通过NSURLSessionDownloadTask并以代理的方式来完成大文件的下载 //监听文件的下载进度 -(void)downloadDelegate { //1.确定请求路径 NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.创建会话对象 self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; //4.创建下载任务 NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request]; //5.执行TASK [downloadTask resume]; // 属性引用 self.downloadTask = downloadTask; }
< NSURLSessionDownloadDelegate > 代理方法
#pragma mark ------------------- #pragma mark NSURLSessionDownloadDelegate //1.写数据的时候调用, 可能会被调用很多次 /* bytesWritten :本次下载数据的大小 totalBytesWritten : 已经下载数据的总大小 totalBytesExpectedToWrite :文件的总大小 */ -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ NSLog(@"当前已经下载了%f",1.0 * totalBytesWritten / totalBytesExpectedToWrite ); }
//2.(取消--继续下载)恢复下载的时候回调用 /* 2.恢复下载的时候调用该方法 fileOffset:恢复之后,要从文件的什么地方开发下载 expectedTotalBytes:该文件数据的总大小 */ -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{ NSLog(@"didResumeAtOffset----"); }
//3.当下载完成的时候调用 -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{ NSLog(@"%@",location); //1.得到caches路径 NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; NSString *fileName = downloadTask.response.suggestedFilename; //2.拼接全路径 NSString *fullPath = [caches stringByAppendingPathComponent:fileName]; //3.剪切文件 /* 第一个参数:要剪切的文件在哪里 NSURL 第二个参数:要剪切到什么地方 NSURL 第三个参数:错误信息 */ [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil]; }
//4.当请求结束的时候调用 // 如果请求失败,那么error有值 -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ NSLog(@"didCompleteWithError"); }