主要思想,就是创建一个与目标文件等大小的空白文件,然后分段往这个空白文件中写入数据。

可以通过发送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开发中多线程断点下载大文件的更多相关文章

  1. iOS 开发中,关于xxx.xcodeproj 文件冲突的解决方案 (以后谁不会了,直接将连接给他)

    iOS 开发中,关于xxx.xcodeproj 文件冲突的解决方案 (一有冲突要手把手教一遍,太麻烦了,现在总结下,以后谁不会了,连接直接发他). 关于xxx.xcodeproj 文件冲突的话,是比较 ...

  2. iOS开发中使用静态库 .a 文件

    ​​iOS开发中,在使用一些第三方库时,可能是一个静态库(比如GPUImage).这种情况下,需要编译出静态库文件(.a) ,然后配合响应的头文件(.h 文件)使用. 编译静态库,直接在Xcode中编 ...

  3. iOS开发中多线程基础

    耗时操作演练 代码演练 编写耗时方法 - (void)longOperation { for (int i = 0; i < 10000; ++i) { NSLog(@"%@ %d&q ...

  4. 在ASP.NET中支持断点续传下载大文件(ZT)

    IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag         客户端每次提交 ...

  5. iOS开发中多线程间关于锁的使用

    为什么需要使用锁,当然熟悉多线程的你,自然不会感到陌生. 那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢? main.m 1 int main(int argc, const ch ...

  6. 在ASP.NET中支持断点续传下载大文件

    IE的自带下载功能中没有断点续传功能,要实现断点续传功能,需要用到HTTP协议中鲜为人知的几个响应头和请求头. 一. 两个必要响应头Accept-Ranges.ETag        客户端每次提交下 ...

  7. IOS开发中多线程的使用

    一.创建多线程的五种方式 1.开启线程的方法一 NSThread * thread=[[NSThread alloc] initWithTarget:self selector:@selector(_ ...

  8. ios开发之多线程---GCD

    一:基本概念 1:进程:正在运行的程序为进程. 2:线程:每个进程要想执行任务必须得有线程,进程中任务的执行都是在线程中. 3:线程的串行:一条线程里任务的执行都是串行的,假如有一个进程开辟了一条线程 ...

  9. iOS开发之多线程技术

    本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解: 一.什么是多线程 1)多线程执行原理 2)线程与进程 3)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...

随机推荐

  1. CentOS 7.0关闭默认firewall防火墙启用iptables防火墙

    操作系统环境:CentOS Linux release 7.0.1406(Core) 64位CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙步骤. 1.关闭f ...

  2. php封装数据库函数

    从Thinkphp里面抽离出来的数据库模块,感觉挺好用 common.php <?PHP /** * 通用函数 */ //包含配置文件 if (is_file("config.php& ...

  3. 更改jdk后,eclipse运行jsp出错

    1.错误: 在Eclipse下启动tomcat的时候,报错为:Eclipse下启动tomcat报错:The archive: C:/Program Files(x86)/Java/jdk1.7.0_1 ...

  4. chrome表单自动填充导致input文本框背景变成偏黄色问题解决

    chrome表单自动填充后,input文本框的背景会变成偏黄色的,想必大家都会碰到这种情况吧, 这是由于chrome会默认给自动填充的input表单加上input:-webkit-autofill私有 ...

  5. C++栈学习——顺序栈和链栈的差别

    C++中栈有顺序栈和链栈之分.在顺序栈中,定义了栈的栈底指针(存储空间首地址base).栈顶指针top以及顺序存储空间的大小stacksize(个人感觉这个数据成员是能够不用定义的) //顺序栈数据结 ...

  6. FreeSWITCH媒体转码配置

    一.说明: FreeSWITCH版本1.6.13二.测试准备 软电话A的语音编码只配置iLBC:软电话B的语音编码只配置PCMU: A->B,编码协商失败,收到488消息. 三.修改文件vars ...

  7. [转]SSH 原理和基本使用:ssh 安全配置 以及ssh key 认证登录

    一.什么是 SSH ? SSH全称(Secure SHell)是一种网络协议,顾名思义就是非常安全的shell,主要用于计算机间加密传输.早期,互联网通信都是基于明文通信,一旦被截获,内容就暴露无遗. ...

  8. Android开发中的神坑和知识点记录

    1.SDK Manager.exe闪退的问题 http://blog.csdn.net/fambit025/article/details/26984345 1.找到android.bat,在源码处找 ...

  9. BIO NIO AIO 简介

    原文: https://github.com/zhongmingmao/nio_demo 简介 NIO与AIO的简单使用 基本概念 同步与异步 同步和异步是针对应用程序和内核的交互而言的:同步指的是用 ...

  10. 从代码上解决Jenkins 发送邮件中文乱码问题

    在实践中,使用Jenkins发送测试报告,收到邮件,邮件内容中的中文为乱码,邮件发送的方式是在Jenkins发邮件设置中设置邮件内容为:${FILE,path="report_ug.html ...