前言
断点续传概述
断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始。当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很浪费时间有木有。所以呢,项目中实现大文件下载的时候,断点续传功能是必不可少了。当然咯,断点续传有一种特殊的情况,就是我们的应用呗用户kill掉或者应用crash,要实现应用重启之后的断点续传,这种情况就是我们将要解决的问题。
断点续传的原理
要实现断点续传,服务器必须是要支持的。目前最常见的两种方式:FTP
和HTTP
。
下面来简单介绍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开发中的断点续传那些事儿的更多相关文章
-
iOS 应用开发中的断点续传实践总结
断点续传概述 断点续传就是从文件上次中断的地方开始重新下载或上传数据,而不是从文件开头.(本文的断点续传仅涉及下载,上传不在讨论之内)当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者 ...
-
iOS开发中关于UIImage的知识点总结
UIImage是iOS中层级比较高的一个用来加载和绘制图像的一个类,更底层的类还有 CGImage,以及iOS5.0以后新增加的CIImage.今天我们主要聊一聊UIImage的三个属性: image ...
-
iOS开发中静态库之";.framework静态库";的制作及使用篇
iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...
-
iOS开发中静态库制作 之.a静态库制作及使用篇
iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...
-
ios开发中的小技巧
在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...
-
IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法
在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...
-
[转]iOS开发中的火星坐标系及各种坐标系转换算法
iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183 其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...
-
iOS开发中常见问题集锦
在iOS开发中,会出现各种各样的问题.今天,就把这些常见的问题以及各位大牛的解决方案汇总下,方便以后查阅: 常见错误: 1. linker command failed with exit code ...
-
iOS开发中获取WiFi相关信息
iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可能是与WiFi相关的. 1.Ping域名.Ping某IP 有 时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作.这里的p ...
随机推荐
-
js 数组 转
1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限, ...
-
CentOS 安装中文输入法
转载:http://blog.sina.com.cn/s/blog_9f1c093101019h03.html centos 6.3用yum安装中文输入法 1.需要root权限,所以要用root登录 ...
-
contentProvider模板
package com.example.qunzheng.todolist.provider; import android.content.ContentProvider; import andro ...
-
TP-LINK wr703n openwrt 挂载 U盘
1.首先设置好DNS 2.点SYSTEM 点SOFTWARE 更新软件列表 3.安装下列软件: block-mount kmod-usb-storage kmod-fs-ext4 e2fsprogs ...
-
C++封装SQLite实例&;lt;三&;gt;
前一篇博客中介绍的是怎样依据sqlite3_get_table()函数来获取一张表的内容,就是一股脑的把表中的内容所有存储起来放在一个一维数组中,这其中的规则已经介绍过了.接下来讲的是怎样依据一个SQ ...
-
LoadRuner12.53教程(二)
使用HP Web访问示例应用程序 shǐ使 yòng用 H P W e b fǎng访 wèn问 shì示 lì例 yìng应 yòng用 chén ...
-
树莓派无显示器开启ssh的方法
在boot根目录新建一个名为 ssh 的空文件即可. boot目录所在分区是fat32格式,可以被windows识别和操作 带有系统的tf卡(或SD卡)插入读卡器中,新建ssh文件即可,注意无后缀名
-
使用外网访问阿里云服务器ZooKeeper
参考网址: zookeeper单机/集群安装详解 使用外网访问阿里云服务器ZooKeeper 阿里云服务管理控制台 1. 阿里云ECS安装zookeeper 环境:我安装的是zookeeper3.4. ...
-
artTemplate 简洁语法版
引用简洁语法的引擎版本,例如: <script src="dist/template.js"></script> 下载 表达式 {{ 与 }} 符号包裹起来 ...
-
Google Protocol Buffers介绍
简要介绍和总结protobuf的一些关键点,从我之前做的ppt里摘录而成,希望能节省protobuf初学者的入门时间.这是一个简单的Demo. Protobuf 简介 Protobuf全称Google ...