斷點續傳功能

#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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章