ios的下载我们可以使用的方法有:NSData、NSURLConnection、NSURLSession还有第三方框架AFNetworking和ASI
利用NSData方法和NSURLConnection的异步方法仅适合下载较小的文件,因为NSData是把数据一口气下载,下载大文件那么手机的内存会一下子暴涨,大文件下载可以用NSURLConnection代理方法、NSURLSession代理方法、AFNetworking和ASI:
NSData:
// 在沙盒中得存储路径
NSString *str = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [str stringByAppendingPathComponent:@"test.exe"];
NSLog(@"%@",str);
// 下载地址
NSURL *url = [NSURL URLWithString:@"http://68.duote.com.cn/fcengw.exe"];
NSData *data = [NSData dataWithContentsOfURL:url];
// 数据写入到沙盒
[data writeToFile:path atomically:YES];
NSURLConnection异步方法:
// 在沙盒中得存储路径
NSString *str = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [str stringByAppendingPathComponent:@"test.exe"];
NSLog(@"%@",str);
// 下载地址
NSURL *url = [NSURL URLWithString:@"http://68.duote.com.cn/fcengw.exe"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 异步方法
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// 数据写入沙盒
[data writeToFile:path atomically:YES];
}];
利用NSURLConnection的代理方法来实现下载(NSURLConnectionDataDelegate):
这其中使用了响应头expectedContentLength来获取文件的总大小,利用了请求头的键“Range”来设置暂停后下一次开始时的位置,利用了NSFileManager和NSFileHandle来设置分段存储下载的数据:
#pragma mark - 属性
// 文件句柄对象
@property (nonatomic,strong) NSFileHandle *fileHandle;
// 文件总长度
@property (nonatomic,assign) long long contentLength;
// 当前文件长度
@property (nonatomic,assign) long long currentLen;
@property (nonatomic,strong) NSURLConnection *conn;
#pragma mark - 点击事件
// 按钮点击事件
- (IBAction)startAndStop {
// 设置按钮选中与否
_btn.selected = !_btn.selected;
// 实现断点续传
if (_btn.selected){ // 按钮选中
// 下载地址
NSString *str = @"http://51.duote.org/haozip_duote.exe";
NSURL *url = [NSURL URLWithString:str];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 设置请求头数据
NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLen];
[request setValue:range forHTTPHeaderField:@"Range"];
self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
}else{
// 取消下载(暂停)
[self.conn cancel];
self.conn = nil;
}
}
#pragma mark - NSURLConnectionDataDelegate代理
// 出错
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"出错 - %@",error.localizedDescription);
}
// 接收到响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (self.currentLen) return;
NSString *cacheStr = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [cacheStr stringByAppendingPathComponent:@"test.exe"];
// 创建一个空的文件
NSFileManager *mgr = [NSFileManager defaultManager];
[mgr createFileAtPath:path contents:nil attributes:nil];
// 句柄对象实例化
self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:path];
// 文件总大小(响应头取得)
NSHTTPURLResponse *resp = (NSHTTPURLResponse *)response;
self.contentLength = resp.expectedContentLength;
}
// 接收数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 找到文件的末尾
[self.fileHandle seekToEndOfFile];
// 在末尾写入数据
[self.fileHandle writeData:data];
// 当前已下载长度
self.currentLen += data.length;
// 下载百分比:当前已下载大小 / 文件总大小
self.progressView.progress = (double)self.currentLen / self.contentLength;
NSLog(@"%f",self.progressView.progress);
}
// 接收完成
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"接收完成");
// 关闭
[self.fileHandle closeFile];
self.fileHandle = nil;
self.currentLen = 0;
self.contentLength = 0;
}
利用NSURLSession的代理方法:
NSURLSession是ios7后才有的方法,苹果官方旨在替代NSURLConnection
NSURLSessionDataTask:解决一般的GET\POST的请求方法
NSURLSessionDownloadTask:解决文件下载
NSURLSessionUploadTask:文件上传
A、NSURLSessionDataTask的操作:
// 下载地址
NSURL *url = [NSURL URLWithString:@"http://68.duote.com.cn/fcengw.exe"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// 这里进行json或XML解析
}];
// 3.开始任务
[task resume];
B、NSURLSessionDownloadTask:不能看到下载进度
// session对象
NSURLSession *session = [NSURLSession sharedSession];
// 下载地址
NSString *str = @"http://51.duote.org/haozip_duote.exe";
// 创建一个下载task
NSURL *url = [NSURL URLWithString:str];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
// 因为任务下载是存在沙盒的temp文件中,并且下载完成后会被立即清除,所以这里将下载的文件剪切到caches中
// location : 临时文件的路径(下载好的文件)
NSString *cacheStr = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// response.suggestedFilename : 建议使用的文件名,一般跟服务器端的文件名一致
NSString *path = [cacheStr stringByAppendingPathComponent:response.suggestedFilename];
// 将临时文件剪切或者复制Caches文件夹
NSFileManager *mgr = [NSFileManager defaultManager];
// AtPath : 剪切前的文件路径
// ToPath : 剪切后的文件路径
[mgr moveItemAtPath:location.path toPath:path error:nil];
}];
// 开始任务
[task resume];
C:NSURLSessionDownloadDelegate的实现:
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
// session对象
NSURLSession *session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 下载task
NSURL *url = [NSURL URLWithString:@"http://51.duote.org/haozip_duote.exe"];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url]; // 这里不要用block,如果用了block,那么方法会优先调用block,而不是代理方法
// 开始任务
[task resume];
#pragma mark - NSURLSessionDownloadDelegate代理
// 下载完毕后调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// response.suggestedFilename : 建议使用的文件名,一般跟服务器端的文件名一致
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 将临时文件剪切或者复制Caches文件夹
NSFileManager *mgr = [NSFileManager defaultManager];
// AtPath : 剪切前的文件路径
// ToPath : 剪切后的文件路径
[mgr moveItemAtPath:location.path toPath:file error:nil];
}
// 恢复下载时调用
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
}
// 每当下载一部分就会调用,可能会被调用多次
// bytesWritten 这次下载了多少
// totalBytesWritten 当前总共下载了多少到沙盒
// totalBytesExpectedToWrite 文件的总大小
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
double progress = (double)totalBytesWritten / totalBytesExpectedToWrite;
NSLog(@"下载进度---%f", progress);
}
D、NSURLSession实现断点续传
// .m文件
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
@property (nonatomic, strong) NSData *resumeData;
@property (nonatomic, strong) NSURLSession *session;
- (NSURLSession *)session
{
if (!_session) {
// 获得session
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:cfg delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
return _session;
}
// 按钮点击事件
- (IBAction)download:(UIButton *)sender {
// 按钮状态取反
sender.selected = !sender.isSelected;
if (self.task == nil) { // 开始(继续)下载
if (self.resumeData) { // 恢复
[self resume];
} else { // 开始
[self start];
}
} else { // 暂停
[self pause];
}
}
// 开始下载
- (void)start
{
// 创建一个下载任务
NSURL *url = [NSURL URLWithString:@"http://xxx.com/mmg/cc.exe"];
self.task = [self.session downloadTaskWithURL:url];
// 开始任务
[self.task resume];
}
// 恢复下载
- (void)resume
{
// 传入上次暂停下载返回的数据,就可以恢复下载
self.task = [self.session downloadTaskWithResumeData:self.resumeData];
// 开始任务
[self.task resume];
// 清空
self.resumeData = nil;
}
// 暂停下载
- (void)pause
{
__weak typeof(self) vc = self;
[self.task cancelByProducingResumeData:^(NSData *resumeData) {
// resumeData : 包含了继续下载的开始位置\下载的url
vc.resumeData = resumeData;
vc.task = nil;
}];
}
#pragma mark - NSURLSessionDownloadDelegate 下载代理方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// response.suggestedFilename : 建议使用的文件名,一般跟服务器端的文件名一致
NSString *file = [caches stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
// 将临时文件剪切或者复制Caches文件夹
NSFileManager *mgr = [NSFileManager defaultManager];
// AtPath : 剪切前的文件路径
// ToPath : 剪切后的文件路径
[mgr moveItemAtPath:location.path toPath:file error:nil];
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
NSLog(@"获得下载进度--%@", [NSThread currentThread]);
// 获得下载进度
self.progressView.progress = (double)totalBytesWritten / totalBytesExpectedToWrite;
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
}