iOS开发之网络编程--使用NSURLConnection实现大文件断点续传下载+使用输出流代替文件句柄
前言:本篇讲解,在前篇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