文件下载 NSURLConnection——文件下载与上传
一、文件下载
重点:NSURLConnection的代理方法不是NSURLConnectionDelegate,而是NSURLConnectionDataDelegate
1.下载小文件,只适合几百k,1、2M的文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | //1.设置网址 //2.加载请求 //3.设置代理 //4.实现代理方法下载文件 NSURL *url = [NSURL URLWithString: @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1492791082124&di=fc642407b4ec19430334653a9b873cff&imgtype=0&src=http%3A%2F%2Fi0.szhomeimg.com%2FUploadFiles%2FBBS%2F2006%2F10%2F24%2F27567833_1950.442.jpg" ]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate :self]; 代理实现 #pragma mark ---NSURLConnectionDelegate - ( void )connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ NSLog( @"下载失败%@" ,error); } //下载响应 - ( void )connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ //获取文件大小 _totalSize = response.expectedContentLength; } //下载数据 - ( void )connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ //拼接数据 [_mudata appendData:data]; //获取当前进度 NSLog( @"%f" ,1.0*_mudata.length/_totalSize); } //下载完成 - ( void )connectionDidFinishLoading:(NSURLConnection *)connection{ NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent: @"1.jpg" ]; [_mudata writeToFile:fullPath atomically:YES]; } |
缺点:[_mudata appendData:data],会使内存暴涨,而且下载完毕后内存不会下降
2.通过句柄来下载大文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #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 )connectionDidFinishLoading:(NSURLConnection *)connection { //1.关闭文件句柄 [self.handle closeFile]; self.handle = nil; NSLog( @"connectionDidFinishLoading" ); NSLog( @"%@" ,self.fullPath); } |
3.通过断点续传来下载大文件(初级版)
设置请求头,如果文件存在就继续下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | //与上面不同的是请求头增加了Range NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSString *Range = [NSString stringWithFormat: @"bytes=%zd" ,_currentSize]; [request setValue:Range forHTTPHeaderField: @"Range" ]; //下面判断文件是否存在不同,如果大于0就返回,不好的地方,删除了文件就不能再下载,待之后完善 //接受响应 - ( void )connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ NSLog( @"%@" ,response); NSLog( @"%@" ,response.MIMEType); //如果放在最前面,文件大小就需要加上当前文件的大小 //如果有下载返回,只适用于当前 //设置沙盒文件 //创建空文件用NSFileManager //句柄指向该文件 _totalSize = response.expectedContentLength+_currentSize; if (_currentSize > 0){ NSLog( @"文件已经下载" ); return ; } _fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent: @"downFile.jpg" ]; //contents内容为空, [[NSFileManager defaultManager] createFileAtPath:_fullPath contents:nil attributes:nil]; _fileHandle = [NSFileHandle fileHandleForWritingAtPath:_fullPath]; } //接受数据 - ( void )connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ //将句柄移动到文件末尾 //通过句柄写入数据 //获取文件进度 if (_currentSize <=1) { _currentSize += data.length; NSLog( @"%f" ,1.0*_currentSize/_totalSize); } [_fileHandle seekToEndOfFile]; [_fileHandle writeData:data]; _progressView.progress = 1.0*_currentSize/_totalSize; } |
缺点:删除了以后不能重新下载
4.文件上传,NSURLConnection上传比较比较奇葩
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | //文件上传 - ( void )fileUpload{ //1.确认请求路径 NSURL *url = [NSURL URLWithString: @"http://120.25.226.186:32812/upload" ]; //2.创建可变请求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //3.设置请求方法 request.HTTPMethod = @"POST" ; //4.设置请求头信息,Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryjv0UfA04ED44AhWx [request setValue:[NSString stringWithFormat: @"multipart/form-data; boundary=%@" ,Kboundary] forHTTPHeaderField: @"Content-Type" ]; //5.拼接请求体参数 NSMutableData *fileData = [NSMutableData data]; /* --分隔符 Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png" Content-Type: image/png(MIMEType:大类型/小类型) 空行 文件参数 */ [fileData appendData:[[NSString stringWithFormat: @"--%@" ,Kboundary] dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; //name:file 服务器规定的参数 //filename:Snip20160225_341.png 文件保存到服务器上面的名称 //Content-Type:文件的类型 [fileData appendData:[ @"Content-Disposition: form-data; name=\" file\"; filename=\"Snip20170424_7.png\"" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:[ @"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:KNewLine]; //image图片 UIImage *image = [UIImage imageNamed: @"Snip20170424_7" ]; //UIImage --->NSData NSData *imageData = UIImagePNGRepresentation(image); [fileData appendData:imageData]; [fileData appendData:KNewLine]; //非文件参数 //分隔符, //非文件参数 /* --分隔符 Content-Disposition: form-data; name="username" 空行 123456 */ [fileData appendData:[[NSString stringWithFormat: @"--%@" ,Kboundary] dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:[ @"Content-Disposition: form-data; name=\" username\"" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; [fileData appendData:KNewLine]; [fileData appendData:[ @"123456" dataUsingEncoding:NSUTF8StringEncoding]]; [fileData appendData:KNewLine]; //结尾标识符 /* --分隔符-- */ [fileData appendData:[[NSString stringWithFormat: @"--%@--" ,Kboundary] dataUsingEncoding:NSUTF8StringEncoding]]; //6.设置请求体,请求体二进制数据 request.HTTPBody = fileData; //发送请求 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { //解析数据 NSLog( @"%@" ,[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]); }]; } |
将来的自己,会感谢现在不放弃的自己!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现