首页 > 代码库 > ios开发网络学习九:NSURLSessionDownloadTask实现大文件下载

ios开发网络学习九:NSURLSessionDownloadTask实现大文件下载

一:NSURLSessionDownloadTask:实现文件下载:无法监听进度

#import "ViewController.h"@interface ViewController ()@end@implementation ViewController-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    [self download];}//优点:不需要担心内存//缺点:无法监听文件下载进度-(void)download{    //1.url    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_03.png"];        //2.创建请求对象    NSURLRequest *request = [NSURLRequest requestWithURL:url];        //3.创建session    NSURLSession *session = [NSURLSession sharedSession];        //4.创建Task    /*     第一个参数:请求对象     第二个参数:completionHandler 回调        location:文件保存的tmp路径url        response:响应头信息        error:错误信息          因为存在tmp路径,所以随时可能会被删除,所以需要手动移动文件夹来存储下载的文件     */    //该方法内部已经实现了边接受数据边写沙盒(tmp)的操作    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {                //6.处理数据        NSLog(@"%@---%@",location,[NSThread currentThread]);                //6.1 拼接文件全路径        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];                //6.2 剪切文件        [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];        NSLog(@"%@",fullPath);    }];        //5.执行Task    [downloadTask resume];}@end

(1)使用NSURLSession和NSURLSessionDownload可以很方便的实现文件下载操作

```objc

 /*

     第一个参数:要下载文件的url路径

     第二个参数:当接收完服务器返回的数据之后调用该block

     location:下载的文件的保存地址(默认是存储在沙盒中tmp文件夹下面,随时会被删除)

     response:服务器响应信息,响应头

     error:该请求的错误信息

     */

    //说明:downloadTaskWithURL方法已经实现了在下载文件数据的过程中边下载文件数据,边写入到沙盒文件的操作

    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * __nullable location, NSURLResponse * __nullable response, NSError * __nullable error)

```

(2)downloadTaskWithURL内部默认已经实现了变下载边写入操作,所以不用开发人员担心内存问题

 

(3)文件下载后默认保存在tmp文件目录,需要开发人员手动的剪切到合适的沙盒目录

 

(4)缺点:没有办法监控下载进度

 

二:NSURLSessionDownloadTask:实现文件下载:监听进度

#import "ViewController.h"@interface ViewController ()<NSURLSessionDownloadDelegate>@end@implementation ViewController-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    [self delegate];}//优点:不需要担心内存//缺点:无法监听文件下载进度-(void)download{    //1.url    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_03.png"];        //2.创建请求对象    NSURLRequest *request = [NSURLRequest requestWithURL:url];        //3.创建session    NSURLSession *session = [NSURLSession sharedSession];        //4.创建Task    /*     第一个参数:请求对象     第二个参数:completionHandler 回调        location:        response:响应头信息        error:错误信息     */    //该方法内部已经实现了边接受数据边写沙盒(tmp)的操作    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {                //6.处理数据        NSLog(@"%@---%@",location,[NSThread currentThread]);                //6.1 拼接文件全路径        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];                //6.2 剪切文件        [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];        NSLog(@"%@",fullPath);    }];        //5.执行Task    [downloadTask resume];}-(void)delegate{    //1.url    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_03.png"];        //2.创建请求对象    NSURLRequest *request = [NSURLRequest requestWithURL:url];        //3.创建session    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];        //4.创建Task    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request];        //5.执行Task    [downloadTask resume];}#pragma mark ----------------------#pragma mark NSURLSessionDownloadDelegate/** *  写数据 * *  @param session                   会话对象 *  @param downloadTask              下载任务 *  @param bytesWritten              本次写入的数据大小 *  @param totalBytesWritten         下载的数据总大小 *  @param totalBytesExpectedToWrite  文件的总大小 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{    //1. 获得文件的下载进度    NSLog(@"%f",1.0 * totalBytesWritten/totalBytesExpectedToWrite);}/** *  当恢复下载的时候调用该方法 * *  @param fileOffset         从什么地方下载 *  @param expectedTotalBytes 文件的总大小 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{    NSLog(@"%s",__func__);}/** *  当下载完成的时候调用 * *  @param location     文件的临时存储路径 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{    NSLog(@"%@",location);        //1 拼接文件全路径    NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];        //2 剪切文件    [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];    NSLog(@"%@",fullPath);}/** *  请求结束 */-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{    NSLog(@"didCompleteWithError");}@end

 

#import "ViewController.h"@interface ViewController ()<NSURLSessionDownloadDelegate>@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;@property (nonatomic, strong) NSData *resumData;@property (nonatomic, strong) NSURLSession *session;@end@implementation ViewController- (IBAction)startBtnClick:(id)sender{    //1.url    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];        //2.创建请求对象    NSURLRequest *request = [NSURLRequest requestWithURL:url];        //3.创建session    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];    self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];        //4.创建Task    NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];        //5.执行Task    [downloadTask resume];        self.downloadTask = downloadTask;}//暂停是可以恢复- (IBAction)suspendBtnClick:(id)sender{    NSLog(@"+++++++++++++++++++暂停");    [self.downloadTask suspend];}//cancel:取消是不能恢复//cancelByProducingResumeData:是可以恢复- (IBAction)cancelBtnClick:(id)sender{    NSLog(@"+++++++++++++++++++取消");    //[self.downloadTask cancel];        //恢复下载的数据!=文件数据    [self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {        self.resumData = resumeData;    }];}- (IBAction)goOnBtnClick:(id)sender{    NSLog(@"+++++++++++++++++++恢复下载");    if(self.resumData)    {        self.downloadTask = [self.session downloadTaskWithResumeData:self.resumData];    }        [self.downloadTask resume];}//优点:不需要担心内存//缺点:无法监听文件下载进度-(void)download{    //1.url    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_03.png"];        //2.创建请求对象    NSURLRequest *request = [NSURLRequest requestWithURL:url];        //3.创建session    NSURLSession *session = [NSURLSession sharedSession];        //4.创建Task    /*     第一个参数:请求对象     第二个参数:completionHandler 回调        location:        response:响应头信息        error:错误信息     */    //该方法内部已经实现了边接受数据边写沙盒(tmp)的操作    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {                //6.处理数据        NSLog(@"%@---%@",location,[NSThread currentThread]);                //6.1 拼接文件全路径        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];                //6.2 剪切文件        [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];        NSLog(@"%@",fullPath);    }];        //5.执行Task    [downloadTask resume];}#pragma mark ----------------------#pragma mark NSURLSessionDownloadDelegate/** *  写数据 * *  @param session                   会话对象 *  @param downloadTask              下载任务 *  @param bytesWritten              本次写入的数据大小 *  @param totalBytesWritten         下载的数据总大小 *  @param totalBytesExpectedToWrite  文件的总大小 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{    //1. 获得文件的下载进度    NSLog(@"%f",1.0 * totalBytesWritten/totalBytesExpectedToWrite);}/** *  当恢复下载的时候调用该方法 * *  @param fileOffset         从什么地方下载 *  @param expectedTotalBytes 文件的总大小 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{    NSLog(@"%s",__func__);}/** *  当下载完成的时候调用 * *  @param location     文件的临时存储路径 */-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{    NSLog(@"%@",location);        //1 拼接文件全路径    NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];        //2 剪切文件    [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];    NSLog(@"%@",fullPath);}/** *  请求结束 */-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{    NSLog(@"didCompleteWithError");}@end

 

 

 

 

 

 

 

(1)创建NSURLSession并设置代理,通过NSURLSessionDownloadTask并以代理的方式来完成大文件的下载

```objc

     //1.创建NSULRSession,设置代理

    self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];

 

    //2.创建task

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];

    self.downloadTask = [self.session downloadTaskWithURL:url];

 

    //3.执行task

    [self.downloadTask resume];

```

(2)常用代理方法的说明

```objc

    /*

 1.当接收到下载数据的时候调用,可以在该方法中监听文件下载的进度

 该方法会被调用多次

 totalBytesWritten:已经写入到文件中的数据大小

 totalBytesExpectedToWrite:目前文件的总大小

 bytesWritten:本次下载的文件数据大小

 */

-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite

/*

 2.恢复下载的时候调用该方法

 fileOffset:恢复之后,要从文件的什么地方开发下载

 expectedTotalBytes:该文件数据的总大小

 */

-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes

/*

 3.下载完成之后调用该方法

 */

-(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location

/*

 4.请求完成之后调用

 如果请求失败,那么error有值

 */

-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error

```

(3)实现断点下载相关代码

```objc

    //如果任务,取消了那么以后就不能恢复了

    //    [self.downloadTask cancel];

 

    //如果采取这种方式来取消任务,那么该方法会通过resumeData保存当前文件的下载信息

    //只要有了这份信息,以后就可以通过这些信息来恢复下载

    [self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {

        self.resumeData = http://www.mamicode.com/resumeData;

    }];

 

    -----------

    //继续下载

    //首先通过之前保存的resumeData信息,创建一个下载任务

    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];

 

     [self.downloadTask resume];

```

(4)计算当前下载进度

 

```objc

    //获取文件下载进度

    self.progress.progress = 1.0 * totalBytesWritten/totalBytesExpectedToWrite;

 ```

 

(5)局限性

 

    01 如果用户点击暂停之后退出程序,那么需要把恢复下载的数据写一份到沙盒,代码复杂度更

    02 如果用户在下载中途未保存恢复下载数据即退出程序,则不具备可操作性

 

---

 

ios开发网络学习九:NSURLSessionDownloadTask实现大文件下载