前言:本篇講解,在前篇iOS開發之網路編程--使用NSURLConnection實現大文件斷點續傳下載的基礎上,使用輸出流代替文件句柄實現大文件斷點續傳。 在實際開發中,輸入輸出流用的比較少,但是用起來也是很方便的。iOS開發用到的輸入輸出流和在Java中的輸入輸出流是幾乎一樣的,本質也是一個意思:
前言:本篇講解,在前篇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 *)connection 115 { 116 NSLog(@"%@",self.fullPath); 117 118 //1.關閉輸出流 119 [self.stream close]; 120 121 //2.清空指針 122 self.stream = nil; 123 } 124 125 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 126 { 127 } 128 129 @end