iOS开发中多线程断点下载大文件
主要思想,就是创建一个与目标文件等大小的空白文件,然后分段往这个空白文件中写入数据。
可以通过发送HEAD请求,获得服务器中文件的具体大小,然后再将这样的长度分割成若干等大的数据块,在发送get请求时,通过设置
请求头信息,可以确定好单个线程中下载文件的起始长度和结束长度。
比如说,目标文件大小事900M,在下载时,开三条线程来下载,size = 300。那么第一条线程就该是0~~299M的任务
第二条线程是300~~599M的任务,第三条则是600M~~最后的大小,当不能整除时,每个size+1,以免造成错误。
在写入文件的适合(这是边下载边写入),通过文件句柄(NSFileHandle)移动到当前下载的文件的末尾,再写入.
当下载完毕,需要关闭当前的文件句柄。
@interface ZYFileDownLoad : NSObject
{
BOOL _downLoading;
}
//是否正在下载
@property (nonatomic, readonly, getter=isDownLoading) BOOL downLoading;
//目标路径,也就是存储路径
@property (nonatomic, copy) NSString *goalPath;
//下载资源的url
@property (nonatomic, copy) NSString *urlStr;
//下载进度
@property (nonatomic, copy) void (^progressHandler)(double progress); //开始下载
- (void)start; //结束下载
- (void)pause;
@end #import "ZYFileDownLoad.h" @implementation ZYFileDownLoad @end
#import "ZYFileDownLoad.h" @interface ZYMultiFileDownLoad : ZYFileDownLoad @end #import "ZYMultiFileDownLoad.h"
#import "ZYSingleDownLoad.h"
#define ZYMaxDownLoadCount 3 @interface ZYMultiFileDownLoad ()
@property (nonatomic, strong) NSMutableArray *singleDownLoads;
@property (nonatomic, assign) long long totalLength;
@end @implementation ZYMultiFileDownLoad
- (void)getFileSize
{
//发送一个HEAD请求,得到服务器响应头中数据的具体信息 Content-Length
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:self.urlStr]];
request.HTTPMethod = @"HEAD";
NSURLResponse *response = nil;
//也可发送异步请求获得信息
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//取得文件大小
self.totalLength = response.expectedContentLength;
} - (NSMutableArray *)singleDownLoads
{
if (_singleDownLoads == nil) {
_singleDownLoads = [NSMutableArray array]; [self getFileSize]; long long size = 0; //每条路径的下载量
if (self.totalLength % ZYMaxDownLoadCount == 0) {
size = self.totalLength / ZYMaxDownLoadCount;
}
else{
size = self.totalLength / ZYMaxDownLoadCount + 1;
} //创建n个下载器
for (int i = 0; i < ZYMaxDownLoadCount; i++) {
ZYSingleDownLoad *singleDownLoad = [[ZYSingleDownLoad alloc] init];
singleDownLoad.urlStr = self.urlStr;
singleDownLoad.goalPath = self.goalPath;
singleDownLoad.beginLength = i * size;
singleDownLoad.endLength = (i + 1) * size - 1;
singleDownLoad.progressHandler = ^(double progress){
//在这里可以设置进度操作
};
[_singleDownLoads addObject:singleDownLoad]; // 创建一个跟服务器文件等大小的临时文件
[[NSFileManager defaultManager] createFileAtPath:self.goalPath contents:nil attributes:nil]; // 让self.goalPath文件的长度是self.totalLengt
NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.goalPath];
[writeHandle truncateFileAtOffset:self.totalLength];
}
}
return _singleDownLoads;
} - (void)start
{
[self.singleDownLoads makeObjectsPerformSelector:@selector(start)];
_downLoading = YES;
} - (void)pause
{
[self.singleDownLoads makeObjectsPerformSelector:@selector(pause)];
_downLoading = NO;
}
@end
@interface ZYSingleDownLoad : ZYFileDownLoad @property (nonatomic, assign) long long beginLength;
@property (nonatomic, assign) long long endLength;
@end #import "ZYSingleDownLoad.h" @interface ZYSingleDownLoad() <NSURLConnectionDataDelegate>
@property (nonatomic, assign) long long currentLength; @property (nonatomic, strong) NSURLConnection *connection; @property (nonatomic, strong) NSFileHandle *writeHandle; @end @implementation ZYSingleDownLoad - (NSFileHandle *)writeHandle
{
if (!_writeHandle) {
_writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.goalPath];
}
return _writeHandle;
} - (void)start
{
NSURL *url = [NSURL URLWithString:self.urlStr]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
//设置请求体,从哪个数据段开始下载
NSString *values = [NSString stringWithFormat:@"bytes=%lld-%lld",self.beginLength + self.currentLength,self.endLength];
[request setValue:values forHTTPHeaderField:@"Range"]; self.connection = [NSURLConnection connectionWithRequest:request delegate:self]; _downLoading = YES;
} - (void)pause
{
[self.connection cancel]; self.connection = nil;
} #pragma mark -------- NSURLConnectionDataDelegate - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{ } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 移动到文件的尾部
[self.writeHandle seekToFileOffset:self.beginLength + self.currentLength];
// 从当前移动的位置(文件尾部)开始写入数据
[self.writeHandle writeData:data]; // 累加长度
self.currentLength += data.length; // 打印下载进度
double progress = (double)self.currentLength / (self.endLength - self.beginLength);
if (self.progressHandler) {
self.progressHandler(progress);
}
} - (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 清空属性值
self.currentLength = 0; // 关闭连接
[self.writeHandle closeFile];
self.writeHandle = nil;
} - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{ }
@end
iOS开发中多线程断点下载大文件的更多相关文章
- iOS 开发中,关于xxx.xcodeproj 文件冲突的解决方案 (以后谁不会了,直接将连接给他)
iOS 开发中,关于xxx.xcodeproj 文件冲突的解决方案 (一有冲突要手把手教一遍,太麻烦了,现在总结下,以后谁不会了,连接直接发他). 关于xxx.xcodeproj 文件冲突的话,是比较 ...
- iOS开发中使用静态库 .a 文件
iOS开发中,在使用一些第三方库时,可能是一个静态库(比如GPUImage).这种情况下,需要编译出静态库文件(.a) ,然后配合响应的头文件(.h 文件)使用. 编译静态库,直接在Xcode中编 ...
- iOS开发中多线程基础
耗时操作演练 代码演练 编写耗时方法 - (void)longOperation { for (int i = 0; i < 10000; ++i) { NSLog(@"%@ %d&q ...
- 在ASP.NET中支持断点续传下载大文件(ZT)
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交 ...
- iOS开发中多线程间关于锁的使用
为什么需要使用锁,当然熟悉多线程的你,自然不会感到陌生. 那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢? main.m 1 int main(int argc, const ch ...
- 在ASP.NET中支持断点续传下载大文件
IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag 客户端每次提交下 ...
- IOS开发中多线程的使用
一.创建多线程的五种方式 1.开启线程的方法一 NSThread * thread=[[NSThread alloc] initWithTarget:self selector:@selector(_ ...
- ios开发之多线程---GCD
一:基本概念 1:进程:正在运行的程序为进程. 2:线程:每个进程要想执行任务必须得有线程,进程中任务的执行都是在线程中. 3:线程的串行:一条线程里任务的执行都是串行的,假如有一个进程开辟了一条线程 ...
- iOS开发之多线程技术
本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解: 一.什么是多线程 1)多线程执行原理 2)线程与进程 3)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...
随机推荐
- 问题 “No mapping found for HTTP request with URI [/fileupload/upload.do]” 的解决
是因为自己springmvc的配置文件里面不小心删除掉了 <!-- 注解扫描 扫描该包下的注解--> <context:component-scan base-package=&qu ...
- Windows Server 2008中安装IIS7.0
最近由于需求重新部署了一台服务器Windows Server 2008,由于以前都是在Windows Server 2003上操作,因此记录下,供其他同学参考. 下面主要介绍在Windows Se ...
- Maven最佳实践:版本管理【转】
什么是版本管理 首先,这里说的版本管理(version management)不是指版本控制(version control),但是本文假设你拥有基本的版本控制的知识,了解subversion的基本用 ...
- MongoDB学习笔记(6)--find
MongoDB 查询文档 MongoDB 查询文档使用 find() 方法. find() 方法以非结构化的方式来显示所有文档. 语法 MongoDB 查询数据的语法格式如下: db.collecti ...
- Oracle 12C -- CDB的启动过程
以启动DB12为例子 $ sqlplus '/as sysdba' SQL*Plus: Release Production on Sun Nov :: Copyright (c) , , Oracl ...
- MySQL -- 全文检索
mysql支持全文索引和全文检索--全文索引的索引类型是fulltext--全文索引只能用于innodb表和myisam表,对应的列类型只是支持char.varchar.text--mysql5.7. ...
- PMD-Java 代码检查工具对 error 和 warning 的配置
PMD是一款优秀的Java程序代码检查工具.该它可以检查Java代码中是否含有未使用的变量.是否含有空的抓取块.是否含有不必要的对象等. 但在使用过程中,你会项目中发现存在大量的 PMD 插件报出的 ...
- Springboot使用junit
1. 首先要下载配套的spring-boot-starter-test包,注意版本要对应. compile("org.springframework.boot:spring-boot-sta ...
- html5 audio组件禁止下载
参考链接:https://wdd.js.org/audio-hide-download-icon.html 1. controlsList=”nodownload”// 这个方法只支持 Chrome ...
- echarts 与 百度地图bmap结合系列: 如何设置地图缩放级别和监听缩放事件
简单的demo: // ehcarts 的实例对象 this.myChart = echarts.init(el) // ehcarts加载完成事件 this.myChart.on('finished ...