大文件下载注意事项


  • 若不对下载的文件进行转存,会造成内存消耗急剧升高,甚至耗尽内存资源,造成程序终止。
  • 在文件下载过程中通常会出现中途停止的状况,若不做处理,就要重新开始下载,浪费流量。

大文件下载的解决方案


  • 对下载文件进行处理,每下载一点数据,就将数据写到磁盘中(通常是沙盒中),避免在内存累积数据(NSURLConnection下载)

    • 使用NSFileHandle类实现写数据
    • 使用NSOutputStream类实现写数据
  • 当下载任务终止时,记录任务终止时的位置信息,以便下次开始继续下载

大文件下载(NSURLConnection)


  • 未支持断点下载
  • 使用NSURLConnection的代理方式下载文件
  • 在下载任务的不同阶段回调的代理方法中,完成转移下载文件,及记录终止位置的任务
  • 使用NSFileHandle类实现写数据的下载步骤(完整核心代码)
    • 设置相关成员属性

      1. /**所要下载文件的总长度*/
      2. @property (nonatomic, assign) NSInteger contentLength;
      3. /**已下载文件的总长度*/
      4. @property (nonatomic, assign) NSInteger currentLength
      5. /**文件句柄,用来实现文件存储*/
      6. @property (nonatomic, strong) NSFileHandle *handle;
    • 创建、发送请求

      1. // 1. 创建请求路径
      2. NSURL *url = [NSURL URLWithString:@"此处为URL字符串"];
      3. // 2. 将URL封装成请求
      4. NSURLRequest *request = [NSURLRequest requestWithURL:url];
      5. // 3. 通过NSURLConnection,并设置代理
      6. [NSURLConnection connectionWithRequest:request delegate:self];
    • 遵守代理协议NSURLConnectionDataDelegate,实现代理方法

      1. /**
      2. * 接收到服务器响应时调用的方法
      3. */
      4. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
      5. {
      6. //获取所要下载文件的总长度
      7. self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue];
      8. //拼接一个沙盒中的文件路径
      9. NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"minion_15.mp4"];
      10. //创建指定路径的文件
      11. [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
      12. //创建文件句柄
      13. self.handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
      14. }
      15. /**
      16. * 接收到服务器的数据时调用的方法
      17. */
      18. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
      19. {
      20. //定位到文件尾部,将服务器每次返回的文件数据都拼接到文件尾部
      21. [self.handle seekToEndOfFile];
      22. //通过文件句柄,将文件写入到沙盒中
      23. [self.handle writeData:data];
      24. //拼接已下载文件总长度
      25. self.currentLength += data.length;
      26. //计算下载进度
      27. CGFloat progress = 1.0 * self.currentLength / self.contentLength;
      28. }
      29. /**
      30. * 文件下载完毕时调用的方法
      31. */
      32. - (void)connectionDidFinishLoading:(NSURLConnection *)connection
      33. {
      34. //关闭文件句柄,并清除
      35. [self.handle closeFile];
      36. self.handle = nil;
      37. //清空已下载文件长度
      38. self.currentLength = 0;
      39. }
  • 使用NSOutputStream类实现写数据的下载步骤(部分代码,其他部分代码同上
    • 设置NSOutputStream成员属性

      1. @property (nonatomic, strong) NSOutputStream *stream;
    • 初始化NSOutputStream对象,打开输出流

      1. /**接收到服务器响应的时候调用*/
      2. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
      3. {
      4. //获取下载数据保存的路径
      5. NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
      6. NSString *filePath = [cache stringByAppendingPathComponent:response.suggestedFilename];
      7. //利用NSOutputStream往filePath文件中写数据,若append参数为yes,则会写到文件尾部
      8. self.stream = [[NSOutputStream alloc] initToFileAtPath:filePath append:YES];
      9. //打开数据流
      10. [self.stream open];
      11. }
    • 写文件数据

      1. /**接收到数据的时候调用*/
      2. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
      3. {
      4. [self.stream write:[data bytes] maxLength:data.length];
      5. }
    • 关闭输出流

      1. /**数据下载完毕的时候调用*/
      2. - (void)connectionDidFinishLoading:(NSURLConnection *)connection
      3. {
      4. [self.stream close];
      5. }

大文件下载(NSURLSession)


  • 支持断点下载,自动记录停止下载时断点的位置
  • 遵守NSURLSessionDownloadDelegate协议
  • 使用NSURLSession下载大文件,被下载文件会被自动写入沙盒的临时文件夹tmp中
  • 下载完毕,通常需要将已下载文件移动其他位置(tmp文件夹中的数据被定时删除),通常是cache文件夹中
  • 详细的下载步骤
    • 设置下载任务task的为成员变量

      1. @property (nonatomic, strong) NSURLSessionDownloadTask *task;
    • 获取NSURLSession对象

      1. NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    • 初始化下载任务任务

      1. self.task = [session downloadTaskWithURL:(此处为下载文件路径URL)];
    • 实现代理方法

      1. /**每当写入数据到临时文件的时候,就会调用一次该方法,通常在该方法中获取下载进度*/
      2. - (void)URLSession:(NSURLSession *)session downloadTask: (NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
      3. {
      4. // 计算下载进度
      5. CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToWrite;
      6. }
      7. /**任务终止时调用的方法,通常用于断点下载*/
      8. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
      9. {
      10. //fileOffset:下载任务中止时的偏移量
      11. }
      12. /**遇到错误的时候调用,error参数只能传递客户端的错误*/
      13. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
      14. { }
      15. /**下载完成的时候调用,需要将文件剪切到可以长期保存的文件夹中*/
      16. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
      17. {
      18. //生成文件长期保存的路径
      19. NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
      20. //获取文件句柄
      21. NSFileManager *fileManager = [NSFileManager defaultManager];
      22. //通过文件句柄,将文件剪切到文件长期保存的路径
      23. [fileManager moveItemAtURL:location toURL:[NSURL fileURLWithPath:file] error:nil];
      24. }
    • 操作任务状态

      1. /**开始/继续下载任务*/
      2. [self.task resume];
      3. /**暂停下载任务*/
      4. [self.task suspend];

iOS网络-04-大文件下载的更多相关文章

  1. IOS NSURLConnection(大文件下载)

    NSURL:请求地址 NSURLRequest:一个NSURLRequest对象就代表一个请求,它包含的信息有 一个NSURL对象 请求方法.请求头.请求体 请求超时 … … NSMutableURL ...

  2. ios开发网络学习三:NSURLConnection小文件大文件下载

    一:小文件下载 #import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDele ...

  3. iOS开发网络请求——大文件的多线程断点下载

    iOS开发中网络请求技术已经是移动app必备技术,而网络中文件传输就是其中重点了.网络文件传输对移动客户端而言主要分为文件的上传和下载.作为开发者从技术角度会将文件分为小文件和大文件.小文件因为文件大 ...

  4. iOS开发之网络编程--小文件下载

    文件下载方式: 如果下载的文件比较小,下载方式: 直接用NSData的 +(id)dataWithContentsOfURL:(NSURL*)url; 利用NSURLConnection发送一个HTT ...

  5. 网络编程---(数据请求+slider)将网络上的大文件下载到本地,并打印其进度

    网络编程---将网络上的大文件下载到本地,并打印其进度. 点击"開始传输"button.将网络上的大文件先下载下来,下载完毕后,保存到本地. UI效果图例如以下: watermar ...

  6. ios网络 -- HTTP请求 and 文件下载/断点下载

    一:请求 http://www.jianshu.com/p/8a90aa6bad6b 二:下载 iOS网络--『文件下载.断点下载』的实现(一):NSURLConnection http://www. ...

  7. iOS开发-大文件下载与断点下载思路

    大文件下载方案一:利用NSURLConnection和它的代理方法,及NSFileHandle(iOS9后不建议使用)相关变量: @property (nonatomic,strong) NSFile ...

  8. iOS网络相关知识总结

    iOS网络相关知识总结 1.关于请求NSURLRequest? 我们经常讲的GET/POST/PUT等请求是指我们要向服务器发出的NSMutableURLRequest的类型; 我们可以设置Reque ...

  9. MTNET 自用ios网络库开源

    短短两天就在https://git.oschina.net/gangwang/MTNET这里收获15个星 github 5星, 值得收藏! MTNET 自用ios网络库开源, 自用很久了,在数歀上架的 ...

随机推荐

  1. ionic 添加应用图标与启动页

    由于手机有很多不同的尺寸与版本,所以图标尺寸也是大小不一,但是如果手动每一个尺寸都制作一个图标,那估计美工会吐血吧,不过幸好,ionic只需要一个图标就可以制作不同尺寸的图标. 添加一个ionic项目 ...

  2. Install Redis on CentOS 6.4--转

    Install Redis on CentOS 6.4 source:http://thoughts.z-dev.org/2013/05/27/install-redis-on-centos-6-4/ ...

  3. @import和link的区别

    @import和link的区别 1.link语法结构    <link href="CSSurl路径" rel="stylesheet" type=&qu ...

  4. doctrine2到底是个什么玩意

    之前和最近一个项目用到了Doctrine,由于是别人搭建的,自己没有很了解,最近又开始做的时候发现拙荆见肘,于是看了一下doctrine教程,本文就是加上自己理解的doctrine教程文档笔记了. D ...

  5. 2015百度之星 IP聚合

    IP聚合 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Descri ...

  6. 重构第10天:提取方法(Extract Method)

    理解:经常写的代码中,有一些计算逻辑比较复杂的方法,写下来一个很长很长的方法,我们可以把这个方法,根据功能,分解成单独的几个小方法.这样做不仅能够增加代码的可维护性,而且增加了易读性. 详解: 重构前 ...

  7. 在Winform开发框架中实现对数据库的加密支持

    在很多情况下,我们需要对数据库进行加密,特别是Access数据库.Sqlite数据库,这些直接部署在客户端的数据,因为数据也是客户的资产,数据库总是存在很多相关的秘密或者重要的业务数据,所以一般来说, ...

  8. Aspose.Word 操作word复杂表格 拆分单元格 复制行 插入行 文字颜色

    private void button3_Click(object sender, EventArgs e)         {             object savePathWord =&q ...

  9. alter语法的简单的使用

    用alter语法来新增列名,修改列名,删除列

  10. X3DOM新增剪裁平面节点ClipPlane支持

    裁剪平面由方程Ax+By+Cz+D=0确定.所有满足[A B C D]M-1[Xe Ye Ze We]T>0的人眼坐标[Xe Ye Ze We]的点都位于该平面定义的半空间中,而该半空间以外的所 ...