前言

断点续传概述

断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始。当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很浪费时间有木有。所以呢,项目中实现大文件下载的时候,断点续传功能是必不可少了。当然咯,断点续传有一种特殊的情况,就是我们的应用呗用户kill掉或者应用crash,要实现应用重启之后的断点续传,这种情况就是我们将要解决的问题。

断点续传的原理

要实现断点续传,服务器必须是要支持的。目前最常见的两种方式:FTPHTTP

下面来简单介绍HTTP断点续传的原理。

HTTP

通过HTTP,可以非常方便的实现断点续传。断点续传主要依赖于HTTP头部定义的Range,应用可以通过HTTP请求曾经获取失败的资源的某一个返回或者部分来恢复下载该资源。当然并不是所有风服务器都支持Range,所以不支持Range的不在我们考虑之内。Range是以字节计算的,请求的时候不比给我结尾字节数,因为请求方并不一定知道资源的大小。
通过这个关键字可以告诉服务器返回哪些数据给我。
比如:
bytes=500-999 表示第500-第999字节
bytes=500- 表示从第500字节往后的所有字节
然后我们再根据服务器返回的数据,将得到的data数据拼接到文件后面,就可以实现断点续传了。

断点续传分析—AFHTTPRequestOperation

在了解了断点续传的原理之后,我们就可以动手来实现iOS中的断点续传了。由于我现在接触到的项目都是部署在HTTP服务器上的,所以断点续传功能也基于HTTP实现。首先我们来最简单的入手,第三方神奇AFNetworking中提供的实现,下面请看详细代码:

 //1.指定下载文件的地址URLString
//2.获取保存的文件路径filePath
//3.获得NSURLRquest
   NSString* URLString = @"";
   NSString* filePath = @"";    NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:URLString]];
   signed long long downloadBytes = 0;
   ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
       // 3.1 若之前下载过 , 则在 HTTP 请求头部加入 Range
       // 获取已下载文件的 size
       downloadedBytes = [self fileSizeForPath:filePath];        // 验证是否下载过文件
       if (downloadedBytes > 0) {
           // 若下载过 , 断点续传的时候修改 HTTP 头部部分的 Range
           NSMutableURLRequest *mutableURLRequest = [request mutableCopy];
           NSString *requestRange =
           [NSString stringWithFormat:@"bytes=%llu-", downloadedBytes];
           [mutableURLRequest setValue:requestRange forHTTPHeaderField:@"Range"];
           request = mutableURLRequest;
       }
   }    // 4 创建 AFHTTPRequestOperation
   AFHTTPRequestOperation *operation
   = [[AFHTTPRequestOperation alloc] initWithRequest:request];    // 5 设置操作输出流 , 保存在第 2 步的文件中
   operation.outputStream = [NSOutputStream
                             outputStreamToFileAtPath:filePath append:YES];    // 6 设置下载进度处理 block
   [operation setDownloadProgressBlock:^(NSUInteger bytesRead,
                                         long long totalBytesRead, long long totalBytesExpectedToRead) {
       // bytesRead 当前读取的字节数
       // totalBytesRead 读取的总字节数 , 包含断点续传之前的
       // totalBytesExpectedToRead 文件总大小
   }];    // 7 设置 success 和 failure 处理 block
   [operation setCompletionBlockWithSuccess:^(
                                              AFHTTPRequestOperation *operation,
                                              id responseObject) {    }                                failure:^(AFHTTPRequestOperation *operation,
                                              NSError *error) {    }];    // 8 启动 operation
   [operation start];

使用以上代码 , 断点续传功能就实现了,应用重新启动或者出现异常情况下 , 都可以基于已经下载的部分开始继续下载。关键的地方就是把已经下载的数据持久化。接下来简单看下AFHTTPRequestOperation是怎么实现的。通过查看源码 , 我们发现 AFHTTPRequestOperation 继承自 AFURLConnectionOperation,而AFURLConnectionOperation 实现了 NSURLConnectionDataDelegate 协议。

处理流程如图所示:

可以看到,这里的AFNetworking采取自线程调一步接口的方式,是因为直接在主线程调用异步接口会有一个Runloop的问题。当主线程调用[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]时,请求发出之后的监听任务会加到主线程中的Runloop中,我们知道RunloopMode默认为NSDefuaultRunloopMode,这个表示只有当前线程的Runloop处理NSDefaultRunloopMode时,这个任务才会执行。而当用户正在滚动tableview和scrollview的时候,主线程的Runloop处于NSEventTrackingRunloop模式下,就不会执行NSDefaultRunloopMode的任务。

另外由于采取子线程调用接口的方式,所以这边的DownloadProgressBlock,success 和 failure Block 都需要回到主线程来处理。

断点续传实战

NSURLConnecttion的实现

NSURLConnecttion这家伙已经在2015年就已经被苹果遗弃,所以在这里我们不做过多讨论,请注意啊,我是省略号……

NSURLSessionDataTask

苹果在iOS7开始,推出一个新的类NSURLSession,它具备了NSURLConnection所具备的方法,并且更加强大。所以我更加推荐大家使用这个类去实现下载和续传。NSURLConnection 和 NSURLSession delegate 方法的映射关系 , 如下图所示。所以关键是要满足 NSURLSessionDataDelegate 和 NSURLsessionTaskDelegate。

文件下载和暂停的实现

当使用NSURLSessionDownloadTask进行下载的时候,系统会在cache文件夹下创建一个下载的路径,路径下会有一个以”CFNetworking”打头的.tmp文件(以下简称”下载文件”防止混淆),这个就是我们正在下载中的文件。而当我们调用了cancelByProducingResumeData:方法后,会得到一个data文件,通过String格式化后,发现是一个XML文件,里面包含了关于.tmp文件的一些关键点的描述,包括”Range”,”key”,”下载文件的路径”等等.而原本存在于download文件下的下载文件,则被移动到了系统tmp文件夹目录下.而当我们再次进行resume操作的时候,下载文件则又被移回到了download文件夹下。

程序被杀掉的断点续传resumeData

根据上面的分析,基本可以得到以下结论:

  • DownloadTask每次进行断点续传的时候,会根据data文件中的”路径Key”去寻找下载文件,然后校验后再根据”Range”属性去进行断点续传。

  • download文件夹中存放的只会是下载中的文件,一旦暂停就会被移动到tmp文件夹下。

  • 每个暂停得到的data文件,与下载文件一一对应。

  • 断点续传只与tmp文件夹中的文件有关。

所以我们可以这么做,设置一个Bool变量用来判断是否正在下载中,同时用一个周期事件每隔一段时间暂停一次。然后保存data文件和拷贝tmp文件夹下的下载文件到安全目录下(因为tmp文件夹据说随时可能清空)。
当再次下载的时候,先是从安全目录下取到下载文件,删除tmp文件夹中原有的同名文件,然后copy到tmp目录下,最后利用保存的data文件进行再次downloadTaskWithResumeData操作,就可以实现再次下载了。

原文链接:总结iOS开发中的断点续传那些事儿

总结iOS开发中的断点续传那些事儿的更多相关文章

  1. iOS 应用开发中的断点续传实践总结

    断点续传概述 断点续传就是从文件上次中断的地方开始重新下载或上传数据,而不是从文件开头.(本文的断点续传仅涉及下载,上传不在讨论之内)当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者 ...

  2. iOS开发中关于UIImage的知识点总结

    UIImage是iOS中层级比较高的一个用来加载和绘制图像的一个类,更底层的类还有 CGImage,以及iOS5.0以后新增加的CIImage.今天我们主要聊一聊UIImage的三个属性: image ...

  3. iOS开发中静态库之".framework静态库"的制作及使用篇

    iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...

  4. iOS开发中静态库制作 之.a静态库制作及使用篇

    iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...

  5. ios开发中的小技巧

    在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...

  6. IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法

    在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...

  7. [转]iOS开发中的火星坐标系及各种坐标系转换算法

     iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183   其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...

  8. iOS开发中常见问题集锦

    在iOS开发中,会出现各种各样的问题.今天,就把这些常见的问题以及各位大牛的解决方案汇总下,方便以后查阅: 常见错误: 1. linker command failed with exit code ...

  9. iOS开发中获取WiFi相关信息

    iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可能是与WiFi相关的. 1.Ping域名.Ping某IP 有 时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作.这里的p ...

随机推荐

  1. Ubuntu下使用nvm

    写在前面:刚写着写着博客就跨年了,希望新的一年大家万事如意,一切向"前"看! 安装 wget -qO- https://raw.githubusercontent.com/crea ...

  2. jsp前端实现分页代码

    前端需要订一page类包装,其参数为 private Integer pageSize=10; //每页记录条数=10 private Integer totalCount; //总记录条数 priv ...

  3. lua 学习笔记(1)

    一.lua函数赋值与函数调用         在lua中函数名也是作为一种变量出现的,即函数和所有其他值一样都是匿名的,当要使用某个函数时,需要将该函数赋值给一个变量,这样在函数块的其他地方就可以通过 ...

  4. 谈谈一些有趣的CSS题目(九)-- 巧妙的实现 CSS 斜线

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  5. MongoDB系列(二):C#应用

    前言 上一篇文章<MongoDB系列(一):简介及安装>已经介绍了MongoDB以及其在window环境下的安装,这篇文章主要讲讲如何用C#来与MongoDB进行通讯.再次强调一下,我使用 ...

  6. EC笔记:第4部分:21、必须返回对象时,别返回引用

    使用应用可以大幅减少构造函数与析构函数的调用次数,但是引用不可以滥用. 如下: struct St { int a; }; St &func(){ St t; return t; } 在返回t ...

  7. ComponentPattern (组合模式)

    import java.util.LinkedList; /** * 组合模式 * * @author TMAC-J 主要用于树状结构,用于部分和整体区别无区别的场景 想象一下,假设有一批连锁的理发店 ...

  8. H3 BPM初次安装常见错误详解1-4

    错误1: 首次安装完成无法访问,效果如下. 错误原因:没有配置IIS. 解决方法: 控制面板-程序-打开或关闭Windows功能,选择internet信息服务. 因为安装的时候没有没有iis,所以程序 ...

  9. git

    CMD命令:git initgit add . [添加文件至暂存区]git commit -m '描述性语句 随意写即可'git branch gh-pages [创建仓库分支]git checkou ...

  10. HP服务器 hp 360g5 centos7安装问题

    HP服务器  hp 360g5 centos7安装问题 一 :启动盘无法识别硬盘 1.进入安装光盘,用上下键选择安装centos--Install Centos7(注意不可按Enter键),如图: 2 ...