iOS開發之網路編程--使用NSURLConnection實現大檔案斷點續傳下載+使用輸出資料流代替檔案控制代碼,nsurlsession斷點續傳
前言:本篇講解,在前篇iOS開發之網路編程--使用NSURLConnection實現大檔案斷點續傳下載的基礎上,使用輸出資料流代替檔案控制代碼實現大檔案斷點續傳。
在實際開發中,輸入輸出資料流用的比較少,但是用起來也是很方便的。iOS開發用到的輸入輸出資料流和在Java中的輸入輸出資料流是幾乎一樣的,本質也是一個意思:將網路返回的資料當做流來處理。
輸入輸出的理解:輸入到哪裡?輸出到哪裡?這個問題不難理解,輸入輸出是要站著伺服器角度來思考的,下面用圖來解釋:
代碼關鍵詞:
1、在接收到回應標頭的代理方法裡建立輸出資料流(根據上面的圖,下載自然需要建立輸出資料流NSOutputStream)。
2、在接收資料的代理方法中寫(write)資料,注意寫入的是data位元組(data.bytes)。
3、最後在下載完畢的代理方法裡關閉輸出資料流。
用來做代碼練習的API介面:
MP4小視頻:http://120.25.226.186:32812/resources/videos/minion_01.mp4
完整的關鍵代碼:
1 #import "ViewController.h" 2 3 @interface ViewController () 4 @property (nonatomic ,assign)NSInteger totalSzie; 5 @property (nonatomic ,assign)NSInteger currentSzie; 6 @property (nonatomic, strong) NSString *fileName; 7 /** 檔案的路徑*/ 8 @property (nonatomic ,strong) NSString *fullPath; 9 /** 請求對象*/ 10 @property (nonatomic ,strong)NSURLConnection *connect; 11 /** 輸出資料流*/ 12 @property (nonatomic ,strong)NSOutputStream *stream; 13 @property (weak, nonatomic) IBOutlet UIProgressView *progressView; 14 @end 15 16 @implementation ViewController 17 #pragma mark ---------------------- 18 #pragma mark Events 19 - (IBAction)downloadBtnClick:(id)sender 20 { 21 22 // [[NSFileManager defaultManager] removeItemAtPath:self.fullPath error:nil]; 23 24 [self download]; 25 } 26 - (IBAction)cancelBtnClick:(id)sender 27 { 28 //取消網路請求 29 [self.connect cancel]; 30 } 31 32 #pragma mark ---------------------- 33 #pragma mark Methods 34 -(void)download 35 { 36 NSLog(@"------"); 37 //1.確定url 38 NSURL *url =[NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]; 39 40 //2.建立請求對象 41 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 42 43 //佈建要求頭資訊,說明只需要請求該資源的一部分資料 44 /* 45 bytes=0-1000 表示下載0~1000的資料 46 bytes=0- 表示從0開始下載直到下載完畢 47 bytes=100- 表示從0開始下載直到下載完畢 48 */ 49 NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSzie]; 50 [request setValue:range forHTTPHeaderField:@"Range"]; 51 NSLog(@"%@",range); 52 53 //3.發送非同步請求 54 self.connect = [NSURLConnection connectionWithRequest:request delegate:self]; 55 } 56 57 #pragma mark ---------------------- 58 #pragma mark NSURLConnectionDataDelegate 59 -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 60 { 61 NSLog(@"--didReceiveResponse-"); 62 63 //判斷是否已經下載過了 64 if (self.currentSzie >0) { 65 return; 66 } 67 68 //0.獲得檔案的總大小 69 //expectedContentLength是本次請求的資料的大小,並不是整個 70 self.totalSzie = response.expectedContentLength; 71 72 //1.得到檔案的名稱 73 self.fileName = response.suggestedFilename; 74 75 //2.獲得檔案的全路徑 76 //caches 77 NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 78 79 NSString *fullPath = [caches stringByAppendingPathComponent:self.fileName]; 80 self.fullPath = fullPath; 81 82 //3.建立輸出資料流 83 /* 84 第一個參數: 寫入資料的地址 85 第二個參數: 表示要不要追加 斷點續傳肯定要追加 86 */ 87 NSOutputStream *stream = [[NSOutputStream alloc]initToFileAtPath:fullPath append:YES]; 88 self.stream = stream; 89 90 //4.開啟資料流 91 // 如果檔案不存在,那麼會自動建立一個空的檔案 92 [self.stream open]; 93 } 94 95 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 96 { 97 //寫資料 98 /* 99 第一個參數:要寫的資料100 第二個參數:資料的長度101 */102 [self.stream write:data.bytes maxLength:data.length];103 104 105 //3.累加當前下載的資料大小106 self.currentSzie +=data.length;107 108 //4.計算檔案的下載進度109 NSLog(@"%f",1.0 * self.currentSzie / self.totalSzie);110 111 self.progressView.progress = 1.0 * self.currentSzie / self.totalSzie;112 }113 114 -(void)connectionDidFinishLoading:(NSURLConnection *)connection115 {116 NSLog(@"%@",self.fullPath);117 118 //1.關閉輸出資料流119 [self.stream close];120 121 //2.清null 指標122 self.stream = nil;123 }124 125 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error126 {127 }128 129 @end