猫猫学Swift之下载-断点续传

猫猫分享,必须精品

原创文章,欢迎转载。转载请注明:翟乃玉的博客
地址:http://www.jianshu.com/notebooks/4236923/latest

下载-断点续传

通过URLSession进行下载,通过OutputStream写入文件,通过URLSessionDataTask来控制下载的继续暂停取消等操作

一:下载过程

1:一次完整的下载流程

1:创建request,session

//request
var request = URLRequest(url: url, cachePolicy:URLRequest.CachePolicy.reloadIgnoringLocalCacheData, 
timeoutInterval: 0)

//session
let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue.main)

2:设置下载偏移量 :offset

request.setValue(String(format: "bytes=%lld-", offset), forHTTPHeaderField: "Range")

3:根据request从会话session中拿到URLSessionDataTask任务,并且继续执行

self.dataTask = self.session.dataTask(with: request)
self.dataTask?.resume()

4:通过session的代理方法,进行数据的传输下载

///主要用到了三个代理方法

 /// 第一次接受到相应的时候调用(响应头, 并没有具体的资源内容)
 /// 通过这个方法里面系统提供的回调代码块(completionHandler) 可以控制:是继续请求, 还是取消本次请求
 func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void);
 
 /// 当用户确定, 继续接受数据的时候调用
 func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data);
 
 /// 请求完成时候调用
 func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?);

4.1第一次接受到相应的时候,保存要下载资源的大小,然后打开输出流,开始下载数据

//创建输出流
let outputStream = OutputStream(toFileAtPath: self.tmpFilePath, append: true)
//打开输出流
outputStream.open()
//开始下载数据
completionHandler(.allow)

如果出现异常,name就取消本次请求,重新开始下载操作

//取消本次请求
completionHandler(.cancel)
//重新开始下载操作
self.downLoad()

4.2当用户确定, 继续接受数据的时候,往输出流中写数据,以及一些其他操作像:进行下载进度,下载速度的计算

// 往输出流中写入数据
data.withUnsafeBytes({ (p: UnsafePointer<UInt8>) -> Void in
    outputStream.write(p, maxLength: data.count)
})
//进行下载进度,下载速度的计算
tmpSize += Int64(data.count)
//计算一秒中的速度
downTask.totalRead += Int64(data.count);
let currentDate = Date()
let time = currentDate.timeIntervalSince(downTask.lastDate)
//当前时间和上一秒时间做对比,大于等于一秒就去计算
if  time >= 1 {
    //计算速度
    let speed = Double(downTask.totalRead) / time
    
    //把速度转成KB或M
    downTask.speed = speed
    
    //维护变量,将计算过的清零
    downTask.totalRead = 0
    //维护变量,记录这次计算的时间
    downTask.lastDate = currentDate
    NYLog("------speed : \(speed)")
}
    
// 记录进度
self.progress = 1.0 * Double(tmpSize) / Double(totalSize)
// 每隔downLoaderConfig.progressMinReturn 秒 闭包返回一次进度
if currentDate.timeIntervalSince(progressLastDate) > downLoaderConfig.progressMinReturn {
    self.progressClosure(self.progress,tmpSize,totalSize)
    progressLastDate = currentDate
}

4.3请求完成时候,成功后移动文件,关闭输出流,清理会话资源


请求完时候成移动文件.png

2:细节:

  1. 下载时候用到两个路径:缓存路径,临时缓存路径
  2. 下载的时候,将数据写入到临时缓存路径当中
  3. 下载完成,将临时缓存路径中下载好的文件移动到缓存路径中
  4. 如果缓存路径里面有url对应的下载文件,那就说明已经下载完成了
  5. 临时缓存是否下载完成, 通过对下载的文件大小和知道的文件大小做对比实现

3:下载文件大小的获取

文件的大小可以通过响应头(response)的Content-Length (或者Content-Range)或者服务器给相应的字段来获取设置.

坑:在续传的时候响应头(response)的Content-Length是变化的, 于是在第一次拿到content-length的时候根据url用UserDefaults进行了一次缓存,然后直接用.

ps:(这个地方可以让后台服务器给,还有的做法会给一个文件的md5,如果能有文件的md5就不需要考虑url是否更改了之类的,当然这些属于业务逻辑上的了,具体还需要根据自己的业务来进行分析)

二:断点续传原理

1:原理

断点续传的工作机制,在HTTP请求头中,有一个Range的关键字,通过这个关键字可以告诉服务器返回哪些数据。
比如:
bytes=500-999 表示第500-第999字节
bytes=500- 表示从第500字节往后的所有字节
然后再根据服务器返回的数据,将得到的data数据拼接到文件后面,就可以实现断点续传了。

2:暂停和续传

暂停和续传网上很多都是运用了resumedata来获取已经下载的信息,但是在ios10 中需要做一些特殊处理, 这里我没有用这种方式,而是通过直接拿到本地已经下载的临时文件的大小,来作为对下一次数据的请求


检测临时文件是否存在.png

Ps: 这里有一个神坑

FileManager.default.attributesOfFileSystem(forPath: )
FileManager.default.attributesOfItem(atPath: )

两个方法返回的都是[FileAttributeKey: Any] 的字典,并且第一个方法有file关键字,理所当然以为是用第一个,但真的应该用第二个

文件大小坑.png

三:其他

关于NSURLSession的一些知识可以看这篇文章
iOS中利用NSURLSession进行文件断点下载

Demo下载地址:https://github.com/znycat/NYDownLoadLib.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容