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)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...
随机推荐
- iscsi target 之LIO配置
LIO 配置 现在主流Linux都可以设置iSCSI,如STGT/TGT.LIO Target等.Linux-IO(LIO)Target是当前Linux标准的iSCSI target的开源实现,包含在 ...
- SQL数据缓存依赖总结
以前只听过SQL server数据缓存依赖,但一直没使用,由于项目需要,才研究了一番,发现了一个很诡异的问题,竟然是一个操作顺序问题导致的. SQL server数据缓存依赖有两种实现模式,轮询模式, ...
- System.ComponentModel.DataAnnotations.Schema 冲突
System.ComponentModel.DataAnnotations.Schema 冲突 Entity Framework 与 .net4.5 的 System.ComponentModel.D ...
- 【Oracle】Oracle中使用转义字符
1.Oracle 特殊字符 转义 关键词:oracle 转义 环境:oracle9i plsql 在plsql ...
- Android如何实现点击一次返回键返回桌面而不是退出应用
具体代码如下所示: @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent. ...
- 一步一步掌握java的线程机制(二)----Thread的生命周期
之前讲到Thread的创建,那是Thread生命周期的第一步,其后就是通过start()方法来启动Thread,它会执行一些内部的管理工作然后调用Thread的run()方法,此时该Thread就是a ...
- SharePoint 2013 创建 Site Collection
在之前的文章中,通过SharePoint Central Administration 创建了Web Application.在这篇文章中将继续SharePoint 2013之旅——还是以Step B ...
- 外部线程停止Java子线程的方法
一.Thread.stop()官方不推荐,Because it is inherently unsafe. 二.方式一1. 线程类示例 public class ThreadT1 implements ...
- Hibernate 连接访问多个数据库(含访问不同数据库的相同表)(转)
利用hibernate访问不同数据库中的不同表或不同数据库中的相同表. 本人在开发过程中的解决方案,希望大家交流.一般用myEclipse工具会自动生成Hibernate的相关文件,大致有下面几类: ...
- iphone5 jail break
dfu恢复恢复备份越狱afc2add删除2个文件,如果只有1个也没问题/var/mobile/Library/Caches/com.apple.mobile.installation.plist/va ...