zoukankan      html  css  js  c++  java
  • 断点续传

    一、重点!重点!重点!

    1、设置数据任务task(从路径中获取文件的长度,再判断是否下载过,来请求url,设置Range,将Range添加到请求头中)。

    2、写入文件(存储下载文件,通过路径设置输出流,并打开,将之前文件取出来,重新设置长度(头文件长度+已下载文件长度),并写入文件)。

    3、写入数据(通过输出流将data写入,并获取到当前下载长度,通过当前下载长度/总长度获取当前下载进度)。

    4、任务完成,关闭输出流,清空任务。

    二、Range的位置

    1.//设置Range头,值:bytes=x-y;x:开始字节,y:结束字节,不指定则为文件末尾

     [request addValue:@"bytes=500-" forHTTPHeaderField:@"Range"];

    2.Range头域

    表示头500个字节:bytes=0-499
    表示第二个500字节:bytes=500-999
    表示最后500个字节:bytes=-500
    表示500字节以后的范围:bytes=500-
    第一个和最后一个字节:bytes=0-0,-1
    同时指定几个范围:bytes=500-600,601-999
    

     三、思维导图

    四、代码如下

    #import "ViewController.h"
    #import "NSString+Md5.h"
    //要下载的文件
    #define fileURL @"http://120.25.226.186:32812/resources/videos/minion_01.mp4"
    //通过md5加密生成唯一的文件名
    #define fileName fileURL.md5String
    //用来存储文件总长度的plist,key:是URL md5加密后的文件名 value:文件的长度
    #define downFilePlist [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"downFile.plist"]
    //下载文件的全路径
    #define downFileFullPath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:fileName]
    //已经下载文件的长度
    #define downFileLength [[[NSFileManager defaultManager]  attributesOfItemAtPath:downFileFullPath error:nil][@"NSFileSize"] integerValue]
    @interface ViewController ()<NSURLSessionDataDelegate>
    //下载分发任务
    @property(nonatomic, strong)NSURLSessionDataTask *dataTask;
    //下载使用
    @property(nonatomic, strong)NSURLSession  *session;
    //输出流
    @property(nonatomic, strong)NSOutputStream *outputStream;
    //文件的总长度
    @property(nonatomic, assign)NSInteger totalLength;
    //下载文件的长度
    @property(nonatomic, assign)NSInteger downLength;
    @end
    @implementation ViewController
    //重新下载或开始下载
    - (IBAction)starDown:(UIButton *)sender {
        [self.dataTask resume];
    }
    //暂停下载
    - (IBAction)pauseDown:(UIButton *)sender {
        [self.dataTask suspend];
    }
    #pragma mark --- getters and setters
    - (NSURLSession *)session{
        if (_session == nil) {
            _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
        }
        return _session;
    }
    - (NSURLSessionDataTask *)dataTask{
        if (_dataTask == nil) {
            //获取文件的总长度
            NSInteger totalLength = [[NSDictionary dictionaryWithContentsOfFile:downFilePlist][fileName] integerValue];
            //请求同一个文件,判断文件是否下载过,如果已下载的文件长度和文件长度相等或有总长度说明下载过
            if(totalLength && totalLength == downFileLength){
                NSLog(@"已经下载过");
                return nil;  
            }
            //否则没有下载过或没有下载完,格式符z和整数转换说明符一起使用,表示对应数字是一个size_t值
            //请求这个URL
            //设置Range
            //设置请求头
            NSMutableURLRequest *request  = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:fileURL]];
            NSString *range = [NSString stringWithFormat:@"bytes=%zd-",downFileLength];
            NSLog(@"%@",range);
            [request setValue:range forHTTPHeaderField:@"Range"];
            _dataTask = [self.session dataTaskWithRequest:request];
        }
        return _dataTask;
    }
    #pragma mark --- NSURLDataDelegate
    /**
      * 接收到响应的时候调用
     */
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveResponse:(NSURLResponse *)response
     completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{
        //调用block才能获取到数据
        completionHandler(NSURLSessionResponseAllow);
        //初始化数据流
        self.outputStream = [NSOutputStream outputStreamToFileAtPath:downFileFullPath append:YES];
        [self.outputStream open]; //打开数据流
        //获取文件总长度
    //    self.totalLength = [response.allHeaderFields[@"Content-Length"] integerValue] + downFileLength;
        self.totalLength = [((NSHTTPURLResponse*)response).allHeaderFields[@"Content-Length"] integerValue] + downFileLength;
        // 接收到服务器响应的时候存储文件的总长度到plist,实现多文件下载,先取出字典,给字典赋值最后写入。
        // 错误做法:直接写入文件,会用这次写入的信息覆盖原来所有的信息
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithContentsOfFile:downFilePlist];
        dic[fileName] = @(self.totalLength);
        [dic writeToFile:downFilePlist atomically:YES];
    }
    //接收服务器发送的数据
    - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
        didReceiveData:(NSData *)data{
        //通过输出流写出数据,获取当前下载的长度/总长度,来获取下载进度
        [self.outputStream write:[data bytes] maxLength:data.length];
        self.downLength = downFileLength;
        NSLog(@"%f",1.0*self.downLength/self.totalLength);
    }
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
        //关闭输出流,并设置为空,清空任务,一个任务对应一个文件
        [self.outputStream close];
        self.outputStream = nil;
        self.dataTask = nil;
        NSLog(@"下载完
    
    将来的自己,会感谢现在不放弃的自己!
  • 相关阅读:
    BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
    BZOJ 2134: 单选错位( 期望 )
    BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )
    BZOJ 2599: [IOI2011]Race( 点分治 )
    BZOJ 3238: [Ahoi2013]差异( 后缀数组 + 单调栈 )
    ZOJ3732 Graph Reconstruction Havel-Hakimi定理
    HDU5653 Bomber Man wants to bomb an Array 简单DP
    HDU 5651 xiaoxin juju needs help 水题一发
    HDU 5652 India and China Origins 并查集
    HDU4725 The Shortest Path in Nya Graph dij
  • 原文地址:https://www.cnblogs.com/TheYouth/p/6517039.html
Copyright © 2011-2022 走看看