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

可以通过发送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. HDU 4324 Triangle LOVE (拓扑排序)

    Triangle LOVE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  2. numpy 的通用函数

    1 CSV文件 CSV,Comma Separate Values,是逗号分隔文件的缩写,是一种存储数据的纯文本格式,通常用于存储电子表格或数据库软件 特点 每条记录占一行 以逗号为分隔符 逗号前后的 ...

  3. “The operation cannot be completed because the DbContext has been disposed” exception with lazy load disabled

    http://stackoverflow.com/questions/18261732/the-operation-cannot-be-completed-because-the-dbcontext- ...

  4. GGSN与SGSN简介

    GPRS核心网是GPRS(general packet radio service)系统的核心部分,GPRS的作用在于传输IP包,广泛应用于2G的GSM和3G的WCDMA网络. 1.GPRS核心网基本 ...

  5. VB的一些项目中常用的通用方法-一般用于验证类

    1.VB的一些项目中常用的通用方法: ' 设置校验键盘输入值,数字 Public Function kyd(key As Integer) As Integer Dim mychar mychar = ...

  6. 【转】WARNING! File system needs to be upgraded. You have version null and I want version 7. Run the '${HBASE_HOME}/bin/hbase migrate' script. 的解决办法

    前段时间集群出问题,hadoop和hbase启动不了了. 后来hadoop回复了,hbase死活master无法启动.打开日志发现报了以下错误: WARNING! File system needs ...

  7. 解决ssh连接慢(有时候等半分钟才出现密码输入提示)的方法

    经常通过ssh 或者 scp 连接一堆远程主机,同样是 Linux 主机,其中一些创建 ssh 连接速度特别慢,连接建立之后执行操作速度却很正常,看来应该不是网络原因.解决的方法是通过ssh 的-v参 ...

  8. unity, 模拟退后台

    //simulateSwitchToBackground.cs using UnityEngine;using System.Collections;using System.Collections. ...

  9. MySQL 5.6学习笔记(数据库基本操作,查看和修改表的存储引擎)

    1. 数据库基本操作 1.1  查看数据库 查看数据库列表: mysql> show databases; +--------------------+ | Database | +------ ...

  10. 关于Java Webproject中web.xml文件

    提及Java Webproject中web.xml文件无人不知,无人不识,呵呵呵:系统首页.servlet.filter.listener和设置session过期时限.张口就来,但是你见过该文件里的e ...