您的位置:首页 > 移动开发 > IOS开发

iOS开发中多线程断点下载大文件

2015-07-25 17:06 218 查看
主要思想,就是创建一个与目标文件等大小的空白文件,然后分段往这个空白文件中写入数据。

可以通过发送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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: