ios开发网络学习三:NSURLConnection小文件大文件下载
一:小文件下载
#import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDelegate> /** 注释 */ @property (nonatomic, strong) NSMutableData *fileData; @property (nonatomic, assign) NSInteger totalSize; @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ViewController -(NSMutableData *)fileData { if (_fileData == nil) { _fileData = [NSMutableData data]; } return _fileData; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self download3]; } //耗时操作[NSData dataWithContentsOfURL:url] -(void)download1 { //1.url NSURL *url = [NSURL URLWithString:@"http://img5.imgtn.bdimg.com/it/u=1915764121,2488815998&fm=21&gp=0.jpg"]; //2.下载二进制数据 NSData *data = [NSData dataWithContentsOfURL:url]; //3.转换 UIImage *image = [UIImage imageWithData:data]; } //1.无法监听进度 //2.内存飙升 -(void)download2 { //1.url // NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/forum/w%3D580/sign=54a8cc6f728b4710ce2ffdc4f3cec3b2/d143ad4bd11373f06c0b5bd1a40f4bfbfbed0443.jpg"]; NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.发送请求 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { //4.转换 // UIImage *image = [UIImage imageWithData:data]; // // self.imageView.image = image; //NSLog(@"%@",connectionError); //4.写数据到沙盒中 NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.mp4"]; [data writeToFile:fullPath atomically:YES]; }]; } //内存飙升 -(void)download3 { //1.url // NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/forum/w%3D580/sign=54a8cc6f728b4710ce2ffdc4f3cec3b2/d143ad4bd11373f06c0b5bd1a40f4bfbfbed0443.jpg"]; NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.发送请求 [[NSURLConnection alloc]initWithRequest:request delegate:self]; } #pragma mark ---------------------- #pragma mark NSURLConnectionDataDelegate /** * 1:当接收到服务器响应的时候调用:只调用一次 * */ -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSLog(@"didReceiveResponse"); //得到文件的总大小(本次请求的文件数据的总大小) self.totalSize = response.expectedContentLength; } /** * 2:当下载数据的时候调用,可能被调用多次:在此方法内部有时需要拼接data,也可以在此方法中获得下载的进度 * */ -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // NSLog(@"%zd",data.length); [self.fileData appendData:data]; //进度=已经下载/文件的总大小 NSLog(@"%f",1.0 * self.fileData.length /self.totalSize); } /** * 3:下载失败的时候的调用 * */ -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { } /** * 4:下载成功的时候调用 * */ -(void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"connectionDidFinishLoading"); //4.写数据到沙盒中 NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.mp4"]; [self.fileData writeToFile:fullPath atomically:YES]; NSLog(@"%@",fullPath); } /** * 三种方法的区别:1:耗时操作[NSData dataWithContentsOfURL:url] 2:sendAsynchronousRequest,无法监听进度 3:可以进行进度的监听,以及对下载完成后数据的处理 */ @end
(1)第一种方式(NSData)
```objc
//使用NSDta直接加载网络上的url资源(不考虑线程)
-(void)dataDownload
{
//1.确定资源路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];
//2.根据URL加载对应的资源
NSData *data = [NSData dataWithContentsOfURL:url];
//3.转换并显示数据
UIImage *image = [UIImage imageWithData:data];
self.imageView.image = image;
}
```
(2)第二种方式(NSURLConnection-sendAsync)
```objc
//使用NSURLConnection发送异步请求下载文件资源
-(void)connectDownload
{
//1.确定请求路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.使用NSURLConnection发送一个异步请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
//4.拿到并处理数据
UIImage *image = [UIImage imageWithData:data];
self.imageView.image = image;
}];
}
```
(3)第三种方式(NSURLConnection-delegate)
```objc
//使用NSURLConnection设置代理发送异步请求的方式下载文件
-(void)connectionDelegateDownload
{
//1.确定请求路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.使用NSURLConnection设置代理并发送异步请求
[NSURLConnection connectionWithRequest:request delegate:self];
}
#pragma mark--NSURLConnectionDataDelegate
//当接收到服务器响应的时候调用,该方法只会调用一次
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//创建一个容器,用来接收服务器返回的数据
self.fileData = [NSMutableData data];
//获得当前要下载文件的总大小(通过响应头得到)
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
self.totalLength = res.expectedContentLength;
NSLog(@"%zd",self.totalLength);
//拿到服务器端推荐的文件名称
self.fileName = res.suggestedFilename;
}
//当接收到服务器返回的数据时会调用
//该方法可能会被调用多次
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// NSLog(@"%s",__func__);
//拼接每次下载的数据
[self.fileData appendData:data];
//计算当前下载进度并刷新UI显示
self.currentLength = self.fileData.length;
NSLog(@"%f",1.0* self.currentLength/self.totalLength);
self.progressView.progress = 1.0* self.currentLength/self.totalLength;
}
//当网络请求结束之后调用
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//文件下载完毕把接受到的文件数据写入到沙盒中保存
//1.确定要保存文件的全路径
//caches文件夹路径
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *fullPath = [caches stringByAppendingPathComponent:self.fileName];
//2.写数据到文件中
[self.fileData writeToFile:fullPath atomically:YES];
NSLog(@"%@",fullPath);
}
//当请求失败的时候调用该方法
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
```
二:大文件下载
#import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDelegate> @property (weak, nonatomic) IBOutlet UIProgressView *progressView; @property (nonatomic, assign) NSInteger totalSize; @property (nonatomic, assign) NSInteger currentSize; /** 文件句柄*/ @property (nonatomic, strong)NSFileHandle *handle; /** 沙盒路径 */ @property (nonatomic, strong) NSString *fullPath; @end @implementation ViewController /** * 1:大文件下载的时候,不断的拼接二进制数据,此时会导致内存的飙升,所以此时应该用文件句柄去写文件,创建一个空文件夹,创建文件句柄对象,将下载的文件一点一点拼接到空文件夹内。在文件下载完毕后,要关闭文件句柄,并设为nil空值 * */ -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self download3]; } //内存飙升 -(void)download3 { //1.url // NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/forum/w%3D580/sign=54a8cc6f728b4710ce2ffdc4f3cec3b2/d143ad4bd11373f06c0b5bd1a40f4bfbfbed0443.jpg"]; NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]; //2.创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; //3.发送请求 [[NSURLConnection alloc]initWithRequest:request delegate:self]; } #pragma mark ---------------------- #pragma mark NSURLConnectionDataDelegate -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSLog(@"didReceiveResponse"); //1.得到文件的总大小(本次请求的文件数据的总大小) self.totalSize = response.expectedContentLength; //2.写数据到沙盒中 self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.mp4"]; //3.创建一个空的文件 [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil]; //4.创建文件句柄(指针) self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath]; } -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { //1.移动文件句柄到数据的末尾 [self.handle seekToEndOfFile]; //2.写数据 [self.handle writeData:data]; //3.获得进度 self.currentSize += data.length; //进度=已经下载/文件的总大小 NSLog(@"%f",1.0 * self.currentSize/self.totalSize); self.progressView.progress = 1.0 * self.currentSize/self.totalSize; //NSLog(@"%@",self.fullPath); } -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { } -(void)connectionDidFinishLoading:(NSURLConnection *)connection { //1.关闭文件句柄 [self.handle closeFile]; self.handle = nil; NSLog(@"connectionDidFinishLoading"); NSLog(@"%@",self.fullPath); } @end
(1)第一种方式(NSData)
```objc
//使用NSDta直接加载网络上的url资源(不考虑线程)
-(void)dataDownload
{
//1.确定资源路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];
//2.根据URL加载对应的资源
NSData *data = [NSData dataWithContentsOfURL:url];
//3.转换并显示数据
UIImage *image = [UIImage imageWithData:data];
self.imageView.image = image;
}
```
(2)第二种方式(NSURLConnection-sendAsync)
```objc
//使用NSURLConnection发送异步请求下载文件资源
-(void)connectDownload
{
//1.确定请求路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.使用NSURLConnection发送一个异步请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
//4.拿到并处理数据
UIImage *image = [UIImage imageWithData:data];
self.imageView.image = image;
}];
}
```
(3)第三种方式(NSURLConnection-delegate)
```objc
//使用NSURLConnection设置代理发送异步请求的方式下载文件
-(void)connectionDelegateDownload
{
//1.确定请求路径
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
//2.创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//3.使用NSURLConnection设置代理并发送异步请求
[NSURLConnection connectionWithRequest:request delegate:self];
}
#pragma mark--NSURLConnectionDataDelegate
//当接收到服务器响应的时候调用,该方法只会调用一次
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//创建一个容器,用来接收服务器返回的数据
self.fileData = [NSMutableData data];
//获得当前要下载文件的总大小(通过响应头得到)
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
self.totalLength = res.expectedContentLength;
NSLog(@"%zd",self.totalLength);
//拿到服务器端推荐的文件名称
self.fileName = res.suggestedFilename;
}
//当接收到服务器返回的数据时会调用
//该方法可能会被调用多次
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// NSLog(@"%s",__func__);
//拼接每次下载的数据
[self.fileData appendData:data];
//计算当前下载进度并刷新UI显示
self.currentLength = self.fileData.length;
NSLog(@"%f",1.0* self.currentLength/self.totalLength);
self.progressView.progress = 1.0* self.currentLength/self.totalLength;
}
//当网络请求结束之后调用
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//文件下载完毕把接受到的文件数据写入到沙盒中保存
//1.确定要保存文件的全路径
//caches文件夹路径
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *fullPath = [caches stringByAppendingPathComponent:self.fileName];
//2.写数据到文件中
[self.fileData writeToFile:fullPath atomically:YES];
NSLog(@"%@",fullPath);
}
//当请求失败的时候调用该方法
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
```
#####5.0 大文件的下载
(1)实现思路
边接收数据边写文件以解决内存越来越大的问题
(2)核心代码
```objc
//当接收到服务器响应的时候调用,该方法只会调用一次
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//0.获得当前要下载文件的总大小(通过响应头得到)
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
self.totalLength = res.expectedContentLength;
NSLog(@"%zd",self.totalLength);
//创建一个新的文件,用来当接收到服务器返回数据的时候往该文件中写入数据
//1.获取文件管理者
NSFileManager *manager = [NSFileManager defaultManager];
//2.拼接文件的全路径
//caches文件夹路径
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *fullPath = [caches stringByAppendingPathComponent:res.suggestedFilename];
self.fullPath = fullPath;
//3.创建一个空的文件
[manager createFileAtPath:fullPath contents:nil attributes:nil];
}
//当接收到服务器返回的数据时会调用
//该方法可能会被调用多次
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//1.创建一个用来向文件中写数据的文件句柄
//注意当下载完成之后,该文件句柄需要关闭,调用closeFile方法
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
//2.设置写数据的位置(追加)
[handle seekToEndOfFile];
//3.写数据
[handle writeData:data];
//4.计算当前文件的下载进度
self.currentLength += data.length;
NSLog(@"%f",1.0* self.currentLength/self.totalLength);
self.progressView.progress = 1.0* self.currentLength/self.totalLength;
}
```