iOS 文件下载,断点下载总结

一、小文件下载,eg:图片

NSURL *url = [NSURL URLWithString:@"图片的地址XXX"];NSData *data = [NSData dataWithContentsOfURL:url];

[UIImage imageWithData:data]

例如:NSURLConnection发送一个异步的Get请求


NSURL* url = [NSURL URLWithString:@"需要下载的地址XXXX"];[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {self.imageView.image = [UIImage imageWithData:data]; }];
上面的方法如果下载大文件会很消耗内存,所以尽量下载小文件

二、NSURLConnection下载大文件
// 发送请求去下载 (创建完conn对象后,会自动发起一个异步请求)
[NSURLConnection connectionWithRequest:request delegate:self];
实现以下代理方法
@property (weak, nonatomic) IBOutlet UIProgressView *myPregress;
@property (nonatomic,strong) NSMutableData* fileData;/** * 文件的总长度 */
@property (nonatomic, assign) long long totalLength;

/** * 1.接收到服务器的响应就会调用 * * 
@param response 响应 */

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{  
self.fileData = [NSMutableData data];  
// 获取要下载的文件的大小  
self.totalLength = response.expectedContentLength;
}

/** *   2.当接收到服务器返回的实体数据时调用(具体内容,这个方法可能会被调用多次) 
* * @param data 这次返回的数据 */

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{  
[self.fileData appendData:data];  
self.myPregress.progress = (double)self.fileData.length / self.totalLength;
}

/** * 3.加载完毕后调用(服务器的数据已经完全返回后) */

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{  
// 拼接文件路径  
NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];  
NSString *file = [cache stringByAppendingPathComponent:response.suggestedFilename];  
// 写到沙盒中  
[self.fileData writeToFile:file atomically:YES];

}
response.expectedContentLength 这句代码下载的文件的大小  
response.suggestedFilename 这句代表获取下载的文件名
用来接受文件的NSMutableData一直都在内存中,会随着文件的下载一直变大,
合理的方式在我们获取一部分data的时候就写入沙盒中,然后释放内存中的data。

这里要用到NSFilehandle这个类,这个类可以实现对文件的读取、写入、更新。
下面总结了一些常用的NSFileHandle的方法,在这个表中,fh是一个NSFileHandle对象,data是一个NSData对象,path是一个NSString 对象,offset是易额Unsigned long long变量。

在接受到响应的时候就在沙盒中创建一个空的文件,然后每次接收到数据的时候就拼接到这个文件的最后面,通过- (unsigned long long)seekToEndOfFile; 这个方法

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{  
// 文件路径  
NSString* ceches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];  
NSString* filepath = [ceches stringByAppendingPathComponent:response.suggestedFilename];  
// 创建一个空的文件到沙盒中  
NSFileManager* mgr = [NSFileManager defaultManager];  
[mgr createFileAtPath:filepath contents:nil attributes:nil];  
// 创建一个用来写数据的文件句柄对象  
self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:filepath];  
// 获得文件的总大小  
self.totalLength = response.expectedContentLength;}

/** * 2.当接收到服务器返回的实体数据时调用(具体内容,这个方法可能会被调用多次) * * @param data 这次返回的数据 */

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{  
// 移动到文件的最后面  
[self.writeHandle seekToEndOfFile];  
// 将数据写入沙盒  
[self.writeHandle writeData:data];  
// 累计写入文件的长度  
self.currentLength += data.length;  
// 下载进度  
self.myPregress.progress = (double)self.currentLength / self.totalLength;}

/** * 3.加载完毕后调用(服务器的数据已经完全返回后) */

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{  
self.currentLength = 0; self.totalLength = 0;  
// 关闭文件  
[self.writeHandle closeFile]; self.writeHandle = nil;
}

NSURLConnection 只提供了一个cancel方法,这并不是暂停,而是取消下载任务。如果要实现断点下载必须要了解HTTP协议中请求头的Range。

不难看出,通过设置请求头的Range我们可以指定下载的位置、大小。
那么我们这样设置bytes=500- 从500字节以后的所有字节,
只需要在didReceiveData中记录已经写入沙盒中文件的大小(self.currentLength),
把这个大小设置到请求头中,因为第一次下载肯定是没有执行过didReceive方法,self.currentLength也就为0,也就是从头开始下。

#pragma mark --按钮点击事件

- (IBAction)btnClicked:(UIButton *)sender {  

// 状态取反  

sender.selected = !sender.isSelected;  

// 断点续传 // 断点下载  

if (sender.selected) { 

// 继续(开始)下载  

// 1.URL  

NSURL *url = [NSURL URLWithString:@"http://localhost:8080//term_app/hdgg.zip"];  

// 2.请求  

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];  

// 设置请求头  

NSString *range = [NSString stringWithFormat:@"bytes=%lld-", self.currentLength];  

[request setValue:range forHTTPHeaderField:@"Range"];  

// 3.下载  

self.connection = [NSURLConnection connectionWithRequest:request delegate:self];  

} else { 

// 暂停  

[self.connection cancel];  

self.connection = nil;  

}

}


三、NSURLSession下载方式(与NSURLConnection不同的是,NSURLSession需要手动设置下载使用NSURLSession就非常简单了,不需要去考虑什么边下载边写入沙盒的问题

NSURL* url = [NSURL URLWithString:@"http://dlsw.baidu.com/sw-search-sp/soft/9d/25765/sogou_mac_32c_V3.2.0.1437101586.dmg"];  

// 得到session对象  

NSURLSession* session = [NSURLSession sharedSession];  

// 创建任务  

NSURLSessionDownloadTask* downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {  


}];  

// 开始任务  

[downloadTask resume];


是不是跟NSURLConnection很像,但仔细看会发现回调的方法里面并没用NSData传回来,多了一个location,顾名思义,location就是下载好的文件写入沙盒的地址,打印一下发现下载好的文件被自动写入的temp文件夹下面了。

不过在下载完成之后会自动删除temp中的文件,所有我们需要做的只是在回调中把文件移动(或者复制,反正之后会自动删除)到caches中。

NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];  

// response.suggestedFilename : 建议使用的文件名,一般跟服务器端的文件名一致  

NSString *file = [caches stringByAppendingPathComponent:response.suggestedFilename];  

// 将临时文件剪切或者复制Caches文件夹  

NSFileManager *mgr = [NSFileManager defaultManager];  

// AtPath : 剪切前的文件路径  

// ToPath : 剪切后的文件路径  

[mgr moveItemAtPath:location.path toPath:file error:nil];

以上方法不能监听下载进度,实现NSURLSession的delegate方法就能监听下载进度

#pragma mark -- NSURLSessionDownloadDelegate

/** * 下载完毕会调用 * * @param location 文件临时地址 */

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidFinishDownloadingToURL:(NSURL *)location{

}

/** * 每次写入沙盒完毕调用 * 在这里面监听下载进度,totalBytesWritten/totalBytesExpectedToWrite * * @param bytesWritten 这次写入的大小 * @param totalBytesWritten 已经写入沙盒的大小 * @param totalBytesExpectedToWrite 文件总大小 */

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWrittentotalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{  

self.pgLabel.text = [NSString stringWithFormat:@"下载进度:%f",(double)totalBytesWritten/totalBytesExpectedToWrite];

}

/** * 恢复下载后调用, */

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffsetexpectedTotalBytes:(int64_t)expectedTotalBytes{

}


任务取消的方法

- (void)cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler;

取消操作以后会调用一个Block,并传入一个resumeData,该参数包含了继续下载文件的位置信息。也就是说,当你下载了10M得文件数据,暂停了。那么你下次继续下载的时候是从第10M这个位置开始的,而不是从文件最开始的位置开始下载。因而为了保存这些信息,所以才定义了这个NSData类型的这个属性:resumeData。这个data只包含了url跟已经下载了多少数据,不会很大,不用担心内存问题。

另外,session还提供了通过resumeData来创建任务的方法

- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

示例程序下载:

https://github.com/hongfenglt/HFDownLoad


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值