美文网首页iOS开发iOS面试
iOS-大文件下载|断点下载|离线下载

iOS-大文件下载|断点下载|离线下载

作者: 梦蕊dream | 来源:发表于2018-06-26 17:11 被阅读400次

    一、文件下载-AFN

    示例代码

    - (void)download{
        AFHTTPSessionManager *manger = [AFHTTPSessionManager manager];
        NSString *url = @"https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2272971454,2583966854&fm=173&app=25&f=JPEG?w=640&h=621&s=72A22FE3401393E95228E0BA03003047";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
        
        NSURLSessionDownloadTask *loadTask = [manger downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
            //下载进度监听
            NSLog(@"Progress:----%.2f%",100.0*downloadProgress.completedUnitCount/downloadProgress.totalUnitCount);
        } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
            NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
            NSLog(@"fullPath:%@",fullPath);
            NSLog(@"targetPath:%@",targetPath);
            return [NSURL fileURLWithPath:fullPath];
        } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
            NSLog(@"filePath:%@",filePath);
        }];
        [loadTask resume];
    }
    

    二、NSURLConnection

    2.1 NSURLConnection下载文件

    需要遵行NSURLConnectionDataDelegate
    [[NSURLConnection alloc] initWithRequest:request delegate:self]默认是主线程中执行,可以设置代理队列开启子线程。注意不能使用主队列,主队列会使代理方法失效。

    开启子线程:
    [self.urlConnect setDelegateQueue:[[NSOperationQueue alloc]init]];

    子线程里创建 NSURLConnection

    如果想子线程里创建 NSURLConnection 并设置代理方法需要如下注意:

    1)connectionWithRequest

    需要手动开启子线程的 RunLoop,并且不能占用默认 Model


    connectionWithRequest

    request
    The URL request to load. The request object is deep-copied as part of the initialization process. Changes made to request after this method returns do not affect the request that is used for the loading process.
    delegate
    The delegate object for the connection. The connection calls methods on this delegate as the load progresses. Delegate methods are called on the same thread that called this method. For the connection to work correctly, the calling thread’s run loop must be operating in the default run loop mode

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSString *url = @"http://xxx.xxx.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        
        //connectionWithRequest:将NSURLConnection对象作为一个 source 添加到当前 runloop 中,默认运行模式
        self.urlConnect = [NSURLConnection connectionWithRequest:request delegate:self];
        
        [self.urlConnect setDelegateQueue:[[NSOperationQueue alloc]init]];
        [[NSRunLoop currentRunLoop] run];
    });
    
    2)initWithRequest
    • [[NSURLConnection alloc] initWithRequest:request delegate:self];
      该方法同上,需要开启子线程的运行循环
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSString *url = @"http://xxx.xxx.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        //断点下载
        NSString *bytes = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
        [request setValue:bytes forHTTPHeaderField:@"Range"];
        
        self.urlConnect = [[NSURLConnection alloc] initWithRequest:request delegate:self];
        [self.urlConnect setDelegateQueue:[[NSOperationQueue alloc]init]];
        [[NSRunLoop currentRunLoop] run];
    });
    
    • [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]
      可不开启运行循环,调用start方法即可。如果 NSURLConnection 对象没有添加到 RunLoop 中,Start 方法会自动添加到 RunLoop 中,如果当前 RunLoop 没有开启,该方法会自动获取当前线程对应的 RunLoop对象并且开启。
      start
    • (void)start;
      Description
      Causes the connection to begin loading data, if it has not already.
      Calling this method is necessary only if you create a connection with the initWithRequest:delegate:startImmediately: method and provide NO for the startImmediately parameter. If you don’t schedule the connection in a run loop or an operation queue before calling this method, the connection is scheduled in the current run loop in the default mode.
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSString *url = @"http:// xxx.xxxx.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        //断点下载
        NSString *bytes = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
        [request setValue:bytes forHTTPHeaderField:@"Range"];
        
        self.urlConnect = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
        [self.urlConnect setDelegateQueue:[[NSOperationQueue alloc]init]];
        [self.urlConnect start];
    });
    

    文件下载示例代码

    @property (nonatomic, strong) NSString *fullPath;
    @property (nonatomic, assign) NSInteger totalSize;
    @property (nonatomic, assign) NSInteger currentSize;
    @property (nonatomic, strong) NSFileHandle *fileHandle;
    
    - (void)download{
        NSString *url = @"http://xxx.xxxx.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
        
        [[NSURLConnection alloc] initWithRequest:request delegate:self];
    }
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
        //文件数据总大小
        self.totalSize = response.expectedContentLength;
        //沙盒路径
        self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"123.mp4"];
        //空文件
        [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
        //文件句柄
        self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
    }
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //
        //1.文件句柄要在文件最后
        [self.fileHandle seekToEndOfFile];
        
        //2.写数据
        [self.fileHandle writeData:data];
        
        self.currentSize += data.length;
        NSLog(@"%.2f%%",100.0*self.currentSize/self.totalSize);
    }
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
        
    }
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        //关闭文件句柄
        [self.fileHandle closeFile];
        self.fileHandle = nil;
    }
    
    

    2.2 NSURLConnection 断点续传

    注意点:

    • 设置请求头 Range 参数
    • 只创建一次文件路径、空文件、文件句柄
    • 获取文件请求数据大小,并不一定是文件总大小

    请求头参数:

    • Range:bytes=x-y 表示请求 从 X 位置起(Y-X+1)个字节
    • Range:bytes=-z 表示请求 最后 Z 个字节
    • Range:bytes=Q- 表示请求Q 字节以后所有内容

    示例代码:

    @property (nonatomic, strong) NSString *fullPath;
    @property (nonatomic, assign) NSInteger totalSize;
    @property (nonatomic, assign) NSInteger currentSize;
    @property (nonatomic, strong) NSFileHandle *fileHandle;
    @property (nonatomic, strong) NSURLConnection *urlConnect;
    
    - (IBAction)startDownloadBtn:(UIButton *)sender {
        [self download];
    }
    - (IBAction)cancelDownloadBtn:(UIButton *)sender {
        [self.urlConnect cancel];
    }
    

    修改过代码:

    - (void)download{
        NSString *url = @"http://video.yuntoo.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        //断点下载
        NSString *bytes = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
        [request setValue:bytes forHTTPHeaderField:@"Range"];
        
        self.urlConnect = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    }
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
        
        if (self.currentSize > 0) {
            return;
        }
        //文件请求数据大小,期望大小,并不定是总文件大小
        self.totalSize = response.expectedContentLength;
        //沙盒路径
        self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"123.mp4"];
        //空文件
        [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
        //文件句柄
        self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
    }
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //
        //1.文件句柄要在文件最后
        [self.fileHandle seekToEndOfFile];
        
        //2.写数据
        [self.fileHandle writeData:data];
        
        self.currentSize += data.length;
        NSLog(@"%.2f%%",100.0*self.currentSize/self.totalSize);
    }
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
        NSLog(@"didFailWithError");
    }
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        //关闭文件句柄
        [self.fileHandle closeFile];
        self.fileHandle = nil;
    }
    

    三、NSURLSession

    使用步骤

    • 使用 NSURLSession 创建 task,执行 task


      task

    3.1 GET

    2种方法都可以。
    dataTaskWithURL 内部会自动将请求路径作为参数创建一个请求对象,不可变
    回调 Block 是在子线程
    dataTaskWithRequest 内部实现边接受数据变写入沙盒操作(tmp)

    - (void)sessionDownload{
        NSString *url = @"http://xxx.xxx.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
        NSURLSession *session = [NSURLSession sharedSession];
        
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"completionHandler");
        }];
        
    //    NSURLSessionDataTask *dataTask = [[session dataTaskWithURL:[NSURL URLWithString:url]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    //        NSLog(@"completionHandler");
    //    }];
        [dataTask resume];
    }
    

    3.2 POST

    NSString *url = @"http://xxx.xxx.com/login";
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    request.HTTPMethod = @"POST";
    request.HTTPBody = [@"username=123&pwd=d41d8cd98f00b204e9800998ecf8427e" dataUsingEncoding:NSUTF8StringEncoding];
    NSURLSession *session = [NSURLSession sharedSession];
    
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"completionHandler");
    }];
    
    //    NSURLSessionDataTask *dataTask = [[session dataTaskWithURL:[NSURL URLWithString:url]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    //        NSLog(@"completionHandler");
    //    }];
    [dataTask resume];
    

    3.3 代理方法

    设置代理

    NSString *url = @"http://img1.dongqiudi.com/fastdfs3/M00/1A/CB/ChOxM1swdjmAGg96AAET60fgKms735.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    [dataTask resume];
    

    代理方法

    //1.接收服务器的响应,默认取消该请求
    //completionHandler 回调 传给系统
    -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    //    NSURLSessionResponseCancel = 0,取消
    //    NSURLSessionResponseAllow = 1,接收
    //    NSURLSessionResponseBecomeDownload = 2,下载任务
    //    NSURLSessionResponseBecomeStream API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0), tvos(9.0)) = 3,下载任务
        completionHandler(NSURLSessionResponseAllow);
        NSLog(@"%s",__func__);
    }
    //2.收到返回数据,多次调用
    //拼接存储数据
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
        NSLog(@"%s",__func__);
    }
    //3.请求结束或失败时调用
    //解析数据
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        NSLog(@"%s",__func__);
    }
    

    3.4 文件下载

    3.4.1 简单方法-downloadTaskWithRequest

    无法监听文件下载进度

    - (void)sessionDownloadFile{
        NSString *url = @"http://img1.dongqiudi.com/fastdfs3/M00/1A/CB/ChOxM1swdjmAGg96AAET60fgKms735.jpg";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
        NSURLSession *session = [NSURLSession sharedSession];
        
        NSURLSessionDataTask *dataTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
            [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
            NSLog(@"%@",fullPath);
        }];
        [dataTask resume];
    }
    
    3.4.2 代理下载

    遵循NSURLSessionDownloadDelegate
    使用NSURLSessionDownloadTask

    - (void)sessionDownloadFile2{
        NSString *url = @"http://img1.dongqiudi.com/fastdfs3/M00/1A/CB/ChOxM1swdjmAGg96AAET60fgKms735.jpg";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
        NSURLSessionDownloadTask *dataTask = [session downloadTaskWithRequest:request];
        [dataTask resume];
    }
    

    代理方法

    /**
     * 写数据
     * @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(@"--%.2f%%",100.0*totalBytesWritten/totalBytesExpectedToWrite);
    }
    /**
     * 恢复下载
     * @param fileOffset 恢复从哪里位置下载
     * @param expectedTotalBytes 文件总大小
     */
    -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
        
    }
    /**
     * 下载完成
     * @param location 文件临时存储路径
     */
    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
        [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
        NSLog(@"%@",fullPath);
    }
    
    /**
     * 请求结束
     */
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        NSLog(@"didCompleteWithError");
    }
    

    3.5 大文件断点下载-NSURLSessionDownloadTask

    注意点:

    • 取消下载的方法,cancel:不可恢复的;cancelByProducingResumeData:可恢复的
    • 继续下载方法需要判断当前是暂停下载还是取消下载
      暂停下载-继续下载:是接上次下载
      取消下载-继续下载:缓存取消下载时resumeData,再进行下载
      取消下载-继续下载-暂停下载-继续下载:缓存取消下载时resumeData-->进行下载-->暂停下载-->是接上次下载
      全局变量
    @property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
    @property (nonatomic, strong) NSData *resumeData;
    @property (nonatomic, strong) NSURLSession *session;
    

    点击方法

    //开始下载
    - (IBAction)startDownloadBtn:(UIButton *)sender {
        [self sessionDownloadFile2];
    //    [self download];
    }
    //取消下载
    - (IBAction)cancelDownloadBtn:(UIButton *)sender {
        NSLog(@"-----------------cancelDownloadBtn");
    //    [self.downloadTask cancel];
        //cancel:不可恢复的
        //cancelByProducingResumeData:可恢复的
        //恢复下载数据!= 文件数据
        [self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
            self.resumeData = resumeData;
        }];
    }
    //暂停下载
    - (IBAction)suspendBtn:(UIButton *)sender {
        NSLog(@"-----------------suspendBtn");
        [self.downloadTask suspend];
    }
    //继续下载
    - (IBAction)goONBtn:(UIButton *)sender {
        NSLog(@"-----------------goONBtn");
    //    NSURLSessionTaskStateRunning = 0,
    //    NSURLSessionTaskStateSuspended = 1,
    //    NSURLSessionTaskStateCanceling = 2,
    //    NSURLSessionTaskStateCompleted = 3,
        if (self.downloadTask.state == NSURLSessionTaskStateCompleted) {
            if (self.resumeData) {
                //resumeData 有值表示取消下载
                self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
            }
        }
        [self.downloadTask resume];
    }
    

    NSURLSessionDownloadTask初始化和代理方法

    
    - (void)sessionDownloadFile2{
        NSString *url = @"http://video.yuntoo.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
        self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
        NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
        [downloadTask resume];
        self.downloadTask = 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(@"%.2f%%",100.0 *totalBytesWritten/totalBytesExpectedToWrite);
    }
    /**
     * 恢复下载
     * @param fileOffset 恢复从哪里位置下载
     * @param expectedTotalBytes 文件总大小
     */
    -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
        
    }
    /**
     * 下载完成
     * @param location 文件临时存储路径
     */
    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
        NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
        [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
        NSLog(@"%@",fullPath);
    }
    
    /**
     * 请求结束
     */
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        NSLog(@"didCompleteWithError");
    }
    

    3.6 大文件离线断点下载-NSURLSessionDataTask

    遵循NSURLSessionDataDelegate
    使用NSURLSessionDataTask

    • 断点下载是从内存中取出当前下载数据的 Size ,然后设置请求头的 Range
    • 离线断点下载是从沙盒中取出已下载的数据的 Size ,然后设置请求头的 Range

    全局变量

    @property (nonatomic, strong) NSString *fullPath;
    @property (nonatomic, assign) NSInteger totalSize;
    @property (nonatomic, assign) NSInteger currentSize;
    @property (nonatomic, strong) NSFileHandle *fileHandle;
    @property (nonatomic, strong) NSURLSessionDataTask *dataTask;
    -(NSString *)fullPath{
        if (_fullPath == nil) {
            _fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"1234.mp4"];
        }
        return _fullPath;
    }
    

    初始化NSURLSessionDataTask

    • 从沙盒缓存中取已下载文件的大小
    • 设置NSMutableURLRequest 的断点下载范围 Range
    -(NSURLSessionDataTask *)dataTask{
        if (_dataTask == nil) {
            NSString *url = @"http://xxx.xxxx.com/dist/ab7b54f3-8df0-4678-babc-15a6e4f642b7.mp4";
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
            NSDictionary *fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.fullPath error:nil];
            self.currentSize = [[fileDict valueForKey:@"NSFileSize"] integerValue];
            NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
            [request setValue:range forHTTPHeaderField:@"Range"];
            NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
            _dataTask = [session dataTaskWithRequest:request];
        }
        return _dataTask;
    }
    

    开始、取消、继续、暂停方法

    //开始下载
    - (IBAction)startDownloadBtn:(UIButton *)sender {
        NSLog(@"-----------------startDownloadBtn");
        [self.dataTask resume];
    }
    //取消下载
    - (IBAction)cancelDownloadBtn:(UIButton *)sender {
        NSLog(@"-----------------cancelDownloadBtn");
        [self.dataTask cancel];
        self.dataTask = nil;
    }
    //暂停下载
    - (IBAction)suspendBtn:(UIButton *)sender {
        NSLog(@"-----------------suspendBtn");
        [self.dataTask suspend];
    }
    //继续下载
    - (IBAction)goONBtn:(UIButton *)sender {
        NSLog(@"-----------------goONBtn");
        [self.dataTask resume];
    }
    
    

    代理方法

    //1.接收服务器的响应,默认取消该请求
    //completionHandler 回调 传给系统
    -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    //    NSURLSessionResponseCancel = 0,取消
    //    NSURLSessionResponseAllow = 1,接收
    //    NSURLSessionResponseBecomeDownload = 2,下载任务
    //    NSURLSessionResponseBecomeStream API_AVAILABLE(macos(10.11), ios(9.0), watchos(2.0),
        if (self.currentSize == 0) {
            [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
        }
        
        self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:_fullPath];
        self.totalSize = response.expectedContentLength+self.currentSize;
        completionHandler(NSURLSessionResponseAllow);
    }
    //2.收到返回数据,多次调用
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
        [self.fileHandle seekToEndOfFile];
        [self.fileHandle writeData:data];
        self.currentSize += data.length;
        NSLog(@"%.2f",100.0* self.currentSize / self.totalSize);
    }
    //3.请求结束或失败时调用
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        [self.fileHandle closeFile];
        self.fileHandle = nil;
        NSLog(@"didCompleteWithError:%@",_fullPath);
    }
    
    

    Session 释放

    -(void)dealloc{
        [self.session invalidateAndCancel];
    }
    


    其他

    输出流

    保存数据
    初始化

    //输出流指向地址没有文件会新建文件
        self.outStream = [[NSOutputStream alloc] initToFileAtPath:self.fullPath append:YES];
        [self.outStream open];
    

    写数据

    [self.outStream write:data.bytes maxLength:data.length];
    

    关闭

     [self.outStream close];
    

    相关文章

      网友评论

        本文标题:iOS-大文件下载|断点下载|离线下载

        本文链接:https://www.haomeiwen.com/subject/wsgaeftx.html