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)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...
随机推荐
- cd及目录快速切换
一.cd ~ 切换到用户目录 二.cd - cd - 返回进入当前目录前所在目录 三.pushd.popd.dirs 在Linux的多目录命令提示符中工作是一种痛苦的事情,但以下这些利用lin ...
- java的几个format
public static String formatDateToString(long date) { SimpleDateFormat formatter = new SimpleDateForm ...
- fedora国内源常见配置
yum install yum-fastestmirror3.rpmfusion源 rpm -ivh http://download1.rpmfusion.org/free/fedora/rpmfus ...
- java反射之获取枚举对象
项目中导入大量枚举对象,用来定义常量.随着带来一个问题,就是每个枚举类都需要通过key来获取对应枚举的需求. public enum ExamType { CRAFT(1, "草稿" ...
- mysql主从复制配置问题
一,基本步骤 1,创建在主从数据上都创建复制账号,权限选上super, replication slave , replication master(选上这个可以方便从库变成主库): 2,配置主库和备 ...
- 文件处理-智能检测编码的工具(chardet)
一.chardet使用方法 问:假如你不知道你要处理的文件是什么编码可怎么办呢? import chardet f = open('通讯录.txt',mode='rb') data = f.read( ...
- 配置IISserver
我们自己开发站点的时候 要在自己的电脑上写网页 然后我们怎么能像我们浏览互联网上的网页一样.而不是直接双击打开网页呢 这时候就要配置IISserver 让自己能够 预览自己站点的效果 以下是 ...
- Linux中SFTP命令
sftp和ftp是两种协议是不同的,sftp是ssh内含的协议,只要sshd服务器启动了,它就可用,它本身不需要ftp服务器启动. 1.常用登陆方式: 格式:sftp <user>@< ...
- js中多个数字运算后值不对(失真)处理方法
最近遇到一个bug ,在js里面计算两个数字相减,633011.20-31296.30 得到的结果居然是601714.89,领导不乐意了说怎么少了0.01,我一听,噶卵达,来达鬼,不可能啊,我Goog ...
- 增加nginx虚拟主机配置文件(conf.d)
有时候我们按照了nginx后发现配置文件只有一个,/etc/nginx/nginx.conf 所有的配置包括虚拟目录也在此文件中配置, 这样当虚拟主机多了管理就有些不方便了, 这是需要我们把配置文件拆 ...