###使用xcode自帶的代理方法。xcode
代理方法: //這個是開始下載時 調用的方法。 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response //這個也是每次都在調用的方法。 data(表明每次下載的數據大小) - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data //這個方法是在下載時一直會調用的。這裏有三個參數。 bytesWritten(表明本次下載下載了多少) totalBytesWritten(表明已經下載了多少) totalBytesExpectedToWrite(表明文件總大小是多少) - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten: (NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; //這個方法在下載完成後 會自動調用。 connection(這個參數是下完完成後 文件的路徑) - (void)connectionDidFinishLoading:(NSURLConnection *)connection;
1)內存不會暴漲 可是找不到下載完畢以後的文件。 2)能夠直接顯示下載進度。服務器
直接設置NSMutableData屬性來接受下載完畢的數據 . 1)內存依然「暴漲」:至關於仍是先將整個文件下載到內存中 而後在寫入沙盒中 2) 沒法直接顯示下載進度。須要手動計算。session
//用已下載的本地路徑去建立handle NSFileHandle * handle = [NSFileHandle fileHandleForWritingAtPath:@"/Users/ym/Desktop/haha.zip"]; //若是handle建立成功 表明本地路徑有文件。 if (handle) { 操做句柄到最後 [handle seekToEndOfFile]; // 拼接文件/寫入文件 [handle writeData:data]; // 關閉句柄 [handle closeFile]; }else{ //本地路徑沒有文件。 就從新建立一個本地文件路徑 [data writeToFile:@"/Users/ym/Desktop/haha.zip" atomically:YES]; }
問題:屢次下載,會直接在以前的文件後拼接文件—>得不到正確的文件數據。app
//首先要根據文件路徑來建立stream 。若是你的這個路徑沒有文件。他會自動給你建立一個文件。atom
NSOutputStream * stream = [NSOutputStream outputStreamToFileAtPath:@" /Users/ym/Desktop/haha.zip" append:YES]; //建立一個屬性。來存儲文件和關閉stream self.stream = stream; //開啓任務。 [self.stream open]; //在方法裏 來拼接data內容。 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [self.stream write:data.bytes maxLength:data.length]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection{ //在下載結束任務後,關閉stream任務。 [self.stream close]; }
這樣的下載任務。仍是會有和handle同樣的問題。屢次下載和暫停下載以後繼續下載。拼接的文件都是錯誤的。url
因此這裏就引入了斷點續傳功能。代理
###用HEAD請求來獲取下載文件的總大小code
//文件路徑 NSString *urlString = @"http://127.0.0.1/music.zip"; NSURL *url = [NSURL URLWithString:urlString]; //建立請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 設置請求方法: request.HTTPMethod = @"HEAD"; // 發送 HEAD 請求. // HEAD 請求使用什麼方法發送? ---- 通常使用同步方式發送HEAD請求. NSURLResponse *response = nil; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL]; //打印出來的就是你的所須要的文件總大小。 NSLog(@"response:%zd",response.expectedContentLength);
//這裏返回值是一個字典。 [[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:NULL];
//這個就是打印字典的信息。 咱們所須要的就是NSFileSize ** NSFileCreationDate = "2016-05-05 12:59:14 +0000"; ** NSFileExtensionHidden = 0; ** NSFileGroupOwnerAccountID = 20; ** NSFileGroupOwnerAccountName = staff; ** NSFileModificationDate = "2016-05-05 12:59:17 +0000"; ** NSFileOwnerAccountID = 501; ** NSFilePosixPermissions = 420; ** NSFileReferenceCount = 1; ** NSFileSize = 573278888; ** NSFileSystemFileNumber = 19578034; ** NSFileSystemNumber = 16777217; ** NSFileType = NSFileTypeRegular;
因此要接收這個字典 同時返回NSFileSize.獲取本地文件已經下載的大小。 知道了已經下載的大小,還有總大小。咱們就能夠根據這兩個數值來進行斷點續傳了。orm
設置請求頭信息。 <1>格式: Range格式: bytes = x-y 從x位置開始下載,下載y個字節。 bytes = x- 從x開始 下載到完畢。 bytes = -x 從開始下載x個字節。 <2>特色: 一旦Range 屬性設置成功,相應的狀態碼就是206ip
//startSize 就是上文提到的dict中的NSFileSize。要把這個oc屬性轉化爲字符串。 //bytes=zd - 就是從你斷點的位置下載到文件結束
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",startSize]; [request setValue:range forHTTPHeaderField:@"Range"];
利用代理NSURLSessionDownloadDelegate 1.主要利用的代理方法。
這個是每次下載都調用的方法。和上邊的同樣。
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
-(NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
NSString * urlString = @"http://127.0.0.1/music.zip"; NSURL * url = [NSURL URLWithString:urlString];
NSURLSession * session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
NSURLSessionDownloadTask * task = [session downloadTaskWithURL:url]; self.oldSession = session; self.task = task; [task resume];
[self.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) { self.resumeData = resumeData; }]; self.task = nil;
if (self.resumeData) { self.task = [self.oldSession downloadTaskWithResumeData:self.resumeData]; [self.task resume]; }