关于-大文件下载
2016-09-01 10:38
162 查看
NSURLConnection下载
NSURLConnection还提供了另外一种发送请求的方式//发送请求去下载(创建完conn对象后,会自动发起一个异步请求) [NSURLConnectionconnectionWithRequest:requestdelegate:self]; 这里用到了代理,那肯定要遵守协议了.遵守NSURLConnectionDataDelegate协议. 进去看看有几个代理方法,其实我们能用到的也就三个。
/** *请求失败时调用(请求超时、网络异常) * *@paramerror错误原因 */ -(void)connection:(NSURLConnection*)connectiondidFailWithError:(NSError*)error { } /** *1.接收到服务器的响应就会调用 * *@paramresponse响应 */ -(void)connection:(NSURLConnection*)connectiondidReceiveResponse:(NSURLResponse*)response { } /** *2.当接收到服务器返回的实体数据时调用(具体内容,这个方法可能会被调用多次) * *@paramdata这次返回的数据 */ -(void)connection:(NSURLConnection*)connectiondidReceiveData:(NSData*)data { } /** *3.加载完毕后调用(服务器的数据已经完全返回后) */ -(void)connectionDidFinishLoading:(NSURLConnection*)connection { }
通过执行下载操作,分别log上面三个方法,会发现didReceiveData这个方法会被频繁的调用,每次都会传回来一部分data,下面是官方api对这个方法的说明[/code]
iscalledwithasingleimmutableNSDataobjecttothedelegate, representingthenextportionofthedataloadedfromtheconnection.Thisistheonlyguaranteedforthedelegatetoreceivethedatafromtheresourceload.
[/code]
由此我们可以知道,这种下载方式是通过这个代理方法每次传回来一部分文件,最终我们把每次传回来的数据合并成一个我们需要的文件。
这时候我们通常想到的方法是定义一个全局的NSMutableData,接受到响应的时候初始化这个MutableData,在didReceiveData方法里面去拼接
[self.totalDataappendData:data];
最后在完成下载的方法里面吧整个MutableData写入沙盒。
代码如下:
@property(weak,nonatomic)IBOutletUIProgressView*myPregress; @property(nonatomic,strong)NSMutableData*fileData; /** *文件的总长度 */ @property(nonatomic,assign)longlongtotalLength; /** *1.接收到服务器的响应就会调用 * *@paramresponse响应 */ -(void)connection:(NSURLConnection*)connectiondidReceiveResponse:(NSURLResponse*)response { self.fileData=[NSMutableDatadata]; //获取要下载的文件的大小 self.totalLength=response.expectedContentLength; } /** *2.当接收到服务器返回的实体数据时调用(具体内容,这个方法可能会被调用多次) * *@paramdata这次返回的数据 */ -(void)connection:(NSURLConnection*)connectiondidReceiveData:(NSData*)data { [self.fileDataappendData:data]; self.myPregress.progress=(double)self.fileData.length/self.totalLength; } /** *3.加载完毕后调用(服务器的数据已经完全返回后) */ -(void)connectionDidFinishLoading:(NSURLConnection*)connection { //拼接文件路径 NSString*cache=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; NSString*file=[cachestringByAppendingPathComponent:response.suggestedFilename]; //写到沙盒中 [self.fileDatawriteToFile:fileatomically:YES]; }
我这里下载的是javajdk。(度娘的地址)
注意:通常大文件下载是需要给用户展示下载进度的。
这个数值是已经下载的数据大小/要下载的文件总大小
已经下载的数据我们可以记录,要下载的文件总大小在服务器返回的响应头里面可以拿到,在接受到响应的方法里执行[/code]
NSHTTPURLResponse*res=(NSHTTPURLResponse*)response; NSDictionary*headerDic=res.allHeaderFields; NSLog(@"%@",headerDic); self.fileLength=[[headerDicobjectForKey:@"Content-Length"]intValue];
[/code]
不得不说苹果太为开发者考虑了,我们不必这么麻烦的去获取文件总大小了,
response.expectedContentLength这句代码就搞定了。
response.suggestedFilename这句代表获取下载的文件名
这样我们确实可以下载文件,最后拿到的文件也能正常运行
但是有个致命的问题,内存!用来接受文件的NSMutableData一直都在内存中,会随着文件的下载一直变大,
所有这种处理方式绝对是不合理的。
合理的方式在我们获取一部分data的时候就写入沙盒中,然后释放内存中的data。
这里要用到NSFilehandle这个类,这个类可以实现对文件的读取、写入、更新。
下面总结了一些常用的NSFileHandle的方法,在这个表中,fh是一个NSFileHandle对象,data是一个NSData对象,path是一个NSString对象,offset是易额Unsignedlonglong变量。
具体关于NSFileHandle的用法各位自行搜索。
在接受到响应的时候就在沙盒中创建一个空的文件,然后每次接收到数据的时候就拼接到这个文件的最后面,通过-(unsignedlonglong)seekToEndOfFile;这个方法
-(void)connection:(NSURLConnection*)connectiondidReceiveResponse:(NSURLResponse*)response { //文件路径 NSString*ceches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES)lastObject]; NSString*filepath=[cechesstringByAppendingPathComponent:response.suggestedFilename]; //创建一个空的文件到沙盒中 NSFileManager*mgr=[NSFileManagerdefaultManager]; [mgrcreateFileAtPath:filepathcontents:nilattributes:nil]; //创建一个用来写数据的文件句柄对象 self.writeHandle=[NSFileHandlefileHandleForWritingAtPath:filepath]; //获得文件的总大小 self.totalLength=response.expectedContentLength; } /** *2.当接收到服务器返回的实体数据时调用(具体内容,这个方法可能会被调用多次) * *@paramdata这次返回的数据 */ -(void)connection:(NSURLConnection*)connectiondidReceiveData:(NSData*)data { //移动到文件的最后面 [self.writeHandleseekToEndOfFile]; //将数据写入沙盒 [self.writeHandlewriteData:data]; //累计写入文件的长度 self.currentLength+=data.length; //下载进度 self.myPregress.progress=(double)self.currentLength/self.totalLength; } /** *3.加载完毕后调用(服务器的数据已经完全返回后) */ -(void)connectionDidFinishLoading:(NSURLConnection*)connection { self.currentLength=0; self.totalLength=0; //关闭文件 [self.writeHandlecloseFile]; self.writeHandle=nil; }
这样在下载过程中内存就会一直很稳定了,并且下载的文件也是没问题的。
[/code]
原文:http://www.90159.com/2016/01/07/ios-big-file-download/
相关文章推荐
- 关于防止文件下载盗链之用js来防止文件地址盗链
- 关于使用LinkButton实现点击超链完成文件下载的功能
- FtpWebRequest(转)---关于C/S中文件的上传,下载,获得文件列表
- 关于asp.net中点击linkbutton下载solution中的文件的问题
- 关于PHP文件下载
- 关于文件下载
- 关于文件上传下载!
- 关于LIFERAY源码及数据库文件下载的地址.
- 关于windows 7 Build 6933 32Bit版本BT下载文件的问题!
- 关于S40从网络下载文件的问题
- 关于使用DataGrid的ButtonColumn,动态添加DataGrid列,实现不定列n个文件的下载功能
- 关于证书文件ie中不能下载的问题
- 关于文件下载的几个问题总结
- 关于jspSmartUpload下载文件,出现getOutputStream() has already been..
- 关于当前安全设置不允许下载文件问题的解决
- 关于在vs.net中的.htm里面添加连接,就会出现下载.ASPX文件的提示?
- 关于文件下载的几个问题总结
- 关于取消 IE7浏览网页弹出 “是否允许下载文件” 提示框
- 关于自定义webbroswer,禁止弹出文件下载窗口的方法
- 关于浏览器下载文件的临时目录