看过很多人写的文件断点下载的项目,包括GitHub上面的,但是有个共同特点不满足需求,或者有点过度封装,过度封装那是有点蛋疼的。。所以哥们我决定来一发。当然,我也不是省油的灯,发表我的观点之前先来讽刺下一段脑残的号称断点下载的代码。。。。。。 你可以在自己的Xcode上搞一搞,但是别忘了导入AFNetworking 3.0的包;先来欣赏一把。。。
断点上传参考 http://blog.csdn.net/chmod_r_755/article/details/73741912
完全没有理解神马叫断点下载,瞎扯犊子
其一:上面的方法较适合小文件下载,比如下载个图片音频什么的
其二:断点下载,断点下载的意思是,我把APP关掉,下次进来可以继续上次我的下载,安装上面的方法,尼玛APP一关一个几十兆的文件还他妈能接着下载吗?
下面来说下我的方法和思路
文件其实归根结底是一种二进制流;文件下载可以这样理解,把一个很大很大的文件分割成一小块一小块,从服务端经网络一块一块的流向客户端,说的比较抽象,来张图
假设服务器上有个文件File 大小是 1200kb , 我们可以把它理解成若干个块(这里我为演示把它分成12个块)每个块是100kb(理想情况仅为了演示),下载文件肯定是从第一个块到第十二块这样下载,才能组合成有一个完整的文件
其实NSURLRequest这个类给我们提供了一个方法
- (void)setValue:(nullableNSString *)value forHTTPHeaderField:(NSString *)field;
那么我们怎么使用了 ?断点下载中我们通常这样用
[request setValue:@"bytes=120-" forHTTPHeaderField:@"Range"];
bytes=120- 这又是个神马鬼了 ?
其实这个鬼还蛮给力的 。。。 就是我们上面提到的块,
如果不使用这个方法默认从 0 下载到最后一个字节
我们有以下几个格式
1: bytes=120- 表示从120字节以后开始下载(包括120字节,这不重要其实)
2: bytes=120-1234 表示下载120-1234字节的数据(包括120字节,包括1234)
3: bytes=0-120 表示从头开始下载到120字节处
4: bytes=-120 表示下载最后120字节
5: bytes=120-1234,1567-2456 表示下载120-1234字节的数据和 1567-2456
重点来说下这个方法 ,
task = [managerdataTaskWithRequest:request uploadProgress:NULLdownloadProgress:^(NSProgress *_Nonnull downloadProgress) {
fileTotalSize = downloadProgress.totalUnitCount;
} completionHandler:^(NSURLResponse *_Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
NSLog(@"%ld ====== ",fileTotalSize);
}];
这个方法是下载的时候获取文件大小的方法。如果你是从 0 字节开始下载的话,downloadProgress.totalUnitCount就是文件的总大小 ,如果你设置了 bytes=120- 那么 这个时候downloadProgress.totalUnitCount就是文件的总大小去掉120 ,这个很重要
好了 贴代码。。。。。 你首先需要导入AFNetworking , 然后在模拟器上运行下,因为模拟器上可以打印出地址
#import "ViewController.h"
#import "AFNetworking.h"
#define URL @"http://7fvipe.com1.z0.glb.clouddn.com/322196.jpg"
#define FILEPATH [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"download/org"]
#define FILEPATHName [FILEPATH stringByAppendingPathComponent:@"test8.png"]
@interface ViewController (){
NSURLSessionDataTask *task;
NSFileHandle *fileHandle;
UILabel *showLabel;
__block NSInteger fileCompleteSize ;
__block NSUInteger fileTotalSize ;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@",FILEPATH);
fileCompleteSize = 0;
fileTotalSize = 0;
UIButton *button1 = [[UIButton alloc ] init];
button1.frame = CGRectMake(10, 40, 80, 100);
[button1 setTitle:@"开始下载" forState:UIControlStateNormal];
[button1 addTarget:self action:@selector(button1) forControlEvents:UIControlEventTouchUpInside];
button1.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:button1];
button1 = [[UIButton alloc ] init];
button1.frame = CGRectMake(110, 40, 80, 100);
[button1 setTitle:@"暂停下载" forState:UIControlStateNormal];
[button1 addTarget:self action:@selector(button2) forControlEvents:UIControlEventTouchUpInside];
button1.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:button1];
button1 = [[UIButton alloc ] init];
button1.frame = CGRectMake(210, 40, 80, 100);
[button1 setTitle:@"继续下载" forState:UIControlStateNormal];
[button1 addTarget:self action:@selector(button3) forControlEvents:UIControlEventTouchUpInside];
button1.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:button1];
showLabel = [[UILabel alloc] init];
showLabel.frame = CGRectMake(0, 200, self.view.frame.size.width, 40);
showLabel.textAlignment = NSTextAlignmentCenter;
showLabel.textColor = [UIColor redColor];
[self.view addSubview:showLabel];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:URL]];
task = [manager dataTaskWithRequest:request uploadProgress:NULL downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
fileTotalSize = downloadProgress.totalUnitCount;
} completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
NSLog(@"%ld ====== ", fileTotalSize);
}];
[manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSURLResponse * _Nonnull response) {
NSFileManager *fma = [NSFileManager defaultManager];
if (![fma fileExistsAtPath:FILEPATH]) {
// 如果没有下载文件的话,就创建一个文件。如果有下载文件的话,则不用重新创建(不然会覆盖掉之前的文件)
BOOL b = [fma createDirectoryAtPath:FILEPATH withIntermediateDirectories:YES attributes:nil error:NULL];
if (b) {
NSLog(@"=============");
}else{
NSLog(@"===###############=====");
}
if (![fma fileExistsAtPath:FILEPATHName]) {
b = [fma createFileAtPath:FILEPATHName contents:nil attributes:nil];
if (b) {
NSLog(@"=============");
}else{
NSLog(@"===###############=====");
}
}
}
fileHandle = [NSFileHandle fileHandleForWritingAtPath:FILEPATHName];
return NSURLSessionResponseAllow;
}];
[manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
long long l = [fileHandle seekToEndOfFile];
[fileHandle writeData:data];
fileCompleteSize += data.length;
NSLog(@"%lld",l);
NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
showLabel.text = [NSString stringWithFormat:@"%ld / %ld",fileCompleteSize,fileTotalSize];
}];
}];
}
-(void)button1{
[task resume];
}
-(void)button2{
[task suspend];
}
-(void)button3{
// [task resume];
[self contiuneAction];
}
-(void)contiuneAction{
if (task) {
task = nil;
}
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:URL]];
NSString *range = [NSString stringWithFormat:@"bytes=%zd-", fileCompleteSize];
[request setValue:range forHTTPHeaderField:@"Range"];
task = [manager dataTaskWithRequest:request uploadProgress:NULL downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
fileTotalSize = downloadProgress.totalUnitCount;
} completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
NSLog(@"%ld ====== ", fileTotalSize);
}];
[manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSURLResponse * _Nonnull response) {
NSFileManager *fma = [NSFileManager defaultManager];
BOOL b = [fma createDirectoryAtPath:FILEPATH withIntermediateDirectories:YES attributes:nil error:NULL];
if (b) {
NSLog(@"=============");
}else{
NSLog(@"===###############=====");
}
if (![fma fileExistsAtPath:FILEPATHName]) {
b = [fma createFileAtPath:FILEPATHName contents:nil attributes:nil];
if (b) {
NSLog(@"=============");
}else{
NSLog(@"===###############=====");
}
}
fileHandle = [NSFileHandle fileHandleForWritingAtPath:FILEPATHName];
return NSURLSessionResponseAllow;
}];
[manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
long long l = [fileHandle seekToEndOfFile];
[fileHandle writeData:data];
fileCompleteSize += data.length;
NSLog(@"%lld",l);
NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
showLabel.text = [NSString stringWithFormat:@"%ld / %ld",fileCompleteSize,fileTotalSize];
}];
}];
[task resume];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
然后, 来张截图 。。。
[taskresume]; 的意思是 继续下载, 那么我建议是 你把下载暂停,然后去WC蹲个十分钟,然后让他继续下载看行不行, 然后你就明白我为什么这么干了。 。