#define kReceiveTotal @"receiveTotal"
#define kTotal @"total"
@interface ViewController ()
@end
/**
一、下載的性能優化
1. 使用一個緩衝Data存儲下載的數據,當緩衝的數據>500kb,將此緩衝數據寫入文件,並且清除緩衝數據,以節約內存
二、斷點續傳的實現思路:
1. 暫停的時候,記錄下載的暫停位置
2. 繼續下載時,設置下載的起始位置
http協議的請求頭的設置:
Range : bytes=0-499 表示頭500個字節
Range : bytes=500-999 表示第二個500字節
Range : bytes=-500 表示最後500個字節
Range : bytes=500- 表示500字節以後的範圍
Range : bytes=0-0,-1 第一個和最後一個字節
3. 續傳寫入文件時,總是從文件末尾追加寫入文件
*/
//緩衝目錄 1.png
//目標目錄 1.png
@implementation ViewController {
//2.下載數據的總大小
double total;
//3.接受數據的大小
double receiveTotal;
//4.緩衝數據
NSMutableData *_bufferData;
//5.下載路徑(緩衝目錄)
NSString *_filePath;
NSURLConnection *_connection;
}
- (void)viewDidLoad {
[super viewDidLoad];
//取得下載大小的數據
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
receiveTotal = [[userDefaults objectForKey:kReceiveTotal] doubleValue];
total = [[userDefaults objectForKey:kTotal] doubleValue];
//顯示上次下載的進度
if (total > 0) {
CGFloat progress = receiveTotal/total;
_progressView.progress = progress;
_progreeLabel.text = [NSString stringWithFormat:@"%.2f%%",progress*100];
}
}
- (IBAction)startAction:(id)sender {
NSURL *url = [NSURL URLWithString:@"http://img31.mtime.cn/pi/2013/03/13/115558.26463213_1280X720.jpg"];
//默認就是GET請求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//設置不緩存
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
#warning 斷點續傳添加的代碼
if (receiveTotal > 0) {
//設置繼續下載的位置
NSString *value = [NSString stringWithFormat:@"bytes=%d-",(int)receiveTotal];
[request setValue:value forHTTPHeaderField:@"Range"];
NSLog(@"繼續下載:%@",request.allHTTPHeaderFields);
}
//發送異步請求
_connection = [NSURLConnection connectionWithRequest:request delegate:self];
//創建文件
//取得字符串的URL
NSString *urlstring = url.absoluteString;
//取得URL的最後一部分
NSString *filename = [urlstring lastPathComponent];
//文件路徑
_filePath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/temp/%@",filename];
//判斷文件是否存在,如果不存在,再創建
if (![[NSFileManager defaultManager] fileExistsAtPath:_filePath]) {
//1.創建文件夾
NSString *dirPath = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/temp"];;
//2.創建文件
[[NSFileManager defaultManager] createFileAtPath:_filePath contents:nil attributes:nil];
}
}
//暫停下載
- (IBAction)pauseAction:(id)sender {
//1.取消下載連接
[_connection cancel];
_connection = nil;
//2.將緩衝數據寫入文件
[self appendFileData:_bufferData];
//3.本地保存下載的位置
#warning 後續在添加
NSUserDefaults *userDetaults = [NSUserDefaults standardUserDefaults];
//保存已接受的大小
[userDetaults setObject:@(receiveTotal) forKey:kReceiveTotal];
[userDetaults setObject:@(total) forKey:kTotal];
//將數據同步寫入文件
[userDetaults synchronize];
}
#pragma mark - NSURLConnection delegate
//1.服務響應
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
_bufferData = [[NSMutableData alloc] init];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
//判斷總大小是否爲0,如果是0,說明從起始位置下載,需要獲取文件大總大小
if (total == 0) {
//取得所有的響應頭
NSDictionary *fields = [httpResponse allHeaderFields];
//取得數據的總大小
NSNumber *length = [fields objectForKey:@"Content-Length"];
total = [length doubleValue];
}
NSLog(@"%@",httpResponse.allHeaderFields);
}
//2.數據的傳輸
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//1.接受傳輸的數據
[_bufferData appendData:data];
//2.接受的數據大小/總大小 = 進度
receiveTotal += data.length;
double progress = receiveTotal / total;
//3.刷新UI
_progressView.progress = progress;
_progreeLabel.text = [NSString stringWithFormat:@"%.2f%%",progress*100];
// NSLog(@"接受了%d字節數據",data.length);
NSLog(@"已接受了%d字節數據",(int)receiveTotal);
//4.判斷緩衝的數據大小是否>10kb
if (_bufferData.length > 10*1000) {
[self appendFileData:_bufferData];
[_bufferData setData:nil];
}
}
//3.數據傳輸完成
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//將最後一個緩衝區數據寫入文件
if (_bufferData.length < 10*1000) {
[self appendFileData:_bufferData];
[_bufferData setData:nil];
}
_progreeLabel.text = @"下載完成";
//將下載完成的文件從緩衝目錄剪切到目標目錄
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *fileName = [_filePath lastPathComponent];
NSString *targetFile = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@",fileName];
//判斷目標文件是否存在,如果存在,就刪除掉
if ([fileManager fileExistsAtPath:targetFile]) {
[fileManager removeItemAtPath:targetFile error:nil];
}
//剪切文件,注意:剪切不能將已存在的文件覆蓋
[fileManager moveItemAtPath:_filePath toPath:targetFile error:nil];
//下載完成之後,將本地保存的下載位置清零
NSUserDefaults *userDefatuls = [NSUserDefaults standardUserDefaults];
[userDefatuls setObject:@(0) forKey:kReceiveTotal];
[userDefatuls setObject:@(0) forKey:kTotal];
//將數據同步寫入文件
[userDefatuls synchronize];
receiveTotal = 0;
total = 0;
}
//將數據追加到文件末尾
- (void)appendFileData:(NSData *)appData {
if (appData.length == 0 || _filePath.length == 0) {
return;
}
// 使用NSFileHandle寫文件,此文件必須已經創建,NSFileHandle是不會創建文件的
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:_filePath];
//將文件的寫入點,定位到文件的末尾
[fileHandle seekToEndOfFile];
[fileHandle writeData:appData];
[fileHandle closeFile];
}
@end