断点续传
暂停继续
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
@property (nonatomic, strong) NSData *resumeData;
- (IBAction)start {
if (self.task != nil) {
NSLog(@"已经存在下载任务 %@", self.task);
if (self.task.state == NSURLSessionTaskStateSuspended) {
[self.task resume];
} else {
[self.task suspend];
}
return;
}
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V4.0.2.dmg"];
NSLog(@"start");
self.task = [self.session downloadTaskWithURL:url];
[self.task resume];
}
下载结束处理
按照 suggestedFilename 保存文件
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSLog(@"%@", location);
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:filePath error:NULL];
}
使用 MD5 URL 保存文件
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSLog(@"%@", location);
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:downloadTask.response.URL.absoluteString.md5String];
NSLog(@"%@", filePath.fileMD5Hash);
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:filePath error:NULL];
}
基本功能实现
@property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
@property (nonatomic, strong) NSData *resumeData;
- (IBAction)start {
if (self.downloadTask != nil) {
NSLog(@"正在玩命下载中...");
return;
}
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V4.0.2.dmg"];
self.downloadTask = [self.session downloadTaskWithURL:url];
[self.downloadTask resume];
}
- (IBAction)pause {
NSLog(@"暂停");
[self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
NSLog(@"pause %tu", resumeData.length);
self.resumeData = resumeData;
self.downloadTask = nil;
}];
}
- (IBAction)resume {
if (self.resumeData == nil) {
NSLog(@"没有续传数据");
return;
}
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
self.resumeData = nil;
[self.downloadTask resume];
}
方法整合
- (IBAction)start {
if (self.task != nil || self.resumeData != nil) {
NSLog(@"已经存在下载任务 %@", self.task);
if (self.resumeData != nil) {
self.task = [self.session downloadTaskWithResumeData:self.resumeData];
[self.task resume];
self.resumeData = nil;
} else {
NSLog(@"取消");
[self.task cancelByProducingResumeData:^(NSData *resumeData) {
NSLog(@"%tu", resumeData.length);
self.resumeData = resumeData;
self.task = nil;
}];
}
return;
}
NSURL *url = [NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V4.0.2.dmg"];
NSLog(@"start");
self.task = [self.session downloadTaskWithURL:url];
[self.task resume];
}
续传数据
- 将续传数据写入磁盘,会发现是一个 plist
- 优化续传代码
/// 返回下载文件 URL 的续传数据路径
///
/// @param url 下载文件的 URL
///
/// @return 续传数据路径
- (NSString *)resumePath:(NSURL *)url {
NSString *resumePath = [NSTemporaryDirectory() stringByAppendingPathComponent:url.absoluteString.md5String];
return [resumePath stringByAppendingPathExtension:@"~resume"];
}
/// 加载 URL 对应的续传数据
///
/// @param url 下载文件的 url
///
/// @return 如果存在返回上次续传数据
- (NSData *)loadResumeData:(NSURL *)url {
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:[self resumePath:url]];
// 提取缓存路径名
NSString *tmpFileName = dict[@"NSURLSessionResumeInfoLocalPath"];
// 重新生成缓存路径名
NSString *fileName = [NSTemporaryDirectory() stringByAppendingPathComponent:[tmpFileName lastPathComponent]];
dict[@"NSURLSessionResumeInfoLocalPath"] = fileName;
// 删除续传文件
[[NSFileManager defaultManager] removeItemAtPath:[self resumePath:url] error:NULL];
// PList 序列化
return [NSPropertyListSerialization dataWithPropertyList:dict format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL];
}