大文件下载注意事项


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

大文件下载的解决方案


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

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

大文件下载(NSURLConnection)


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

    • 设置相关成员属性

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

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

      /**
      * 接收到服务器响应时调用的方法
      */
      - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
      {
      //获取所要下载文件的总长度
      self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue];
      //拼接一个沙盒中的文件路径
      NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"minion_15.mp4"];
      //创建指定路径的文件
      [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
      //创建文件句柄
      self.handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
      }
      /**
      * 接收到服务器的数据时调用的方法
      */
      - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
      {
      //定位到文件尾部,将服务器每次返回的文件数据都拼接到文件尾部
      [self.handle seekToEndOfFile];
      //通过文件句柄,将文件写入到沙盒中
      [self.handle writeData:data];
      //拼接已下载文件总长度
      self.currentLength += data.length;
      //计算下载进度
      CGFloat progress = 1.0 * self.currentLength / self.contentLength;
      }
      /**
      * 文件下载完毕时调用的方法
      */
      - (void)connectionDidFinishLoading:(NSURLConnection *)connection
      {
      //关闭文件句柄,并清除
      [self.handle closeFile];
      self.handle = nil;
      //清空已下载文件长度
      self.currentLength = 0;
      }
  • 使用NSOutputStream类实现写数据的下载步骤(部分代码,其他部分代码同上

    • 设置NSOutputStream成员属性

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

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

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

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

大文件下载(NSURLSession)


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

    • 设置下载任务task的为成员变量

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

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

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

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

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

OC - 16.大文件下载的更多相关文章

  1. 2016 - 1- 24 大文件下载 关于NSOutStream 的使用补充

    // // ViewController.m // 大文件下载 // // Created by Mac on 16/1/24. // Copyright © 2016年 Mac. All right ...

  2. python 全栈开发,Day36(作业讲解(大文件下载以及进度条展示),socket的更多方法介绍,验证客户端链接的合法性hmac,socketserver)

     先来回顾一下昨天的内容 黏包现象粘包现象的成因 : tcp协议的特点 面向流的 为了保证可靠传输 所以有很多优化的机制 无边界 所有在连接建立的基础上传递的数据之间没有界限 收发消息很有可能不完全相 ...

  3. IOS-网络(大文件下载)

    一.不合理方式 // // ViewController.m // IOS_0131_大文件下载 // // Created by ma c on 16/1/31. // Copyright © 20 ...

  4. 036_python的大文件下载以及进度条展示

    复习 1.黏包现象 粘包现象的成因: tcp协议的特点,面向流的,为了保证可靠传输,所以有很多优化的机制. 无边界 所有在连接建立的基础上传递的数据之间没有界限. 收发消息很有可能不完全相等. 缓存机 ...

  5. ASP.NET 大文件下载的实现思路及代码

    文件下载是一个网站最基本的功能,ASP.NET网站的文件下载功能实现也很简单,但是如果遇到大文件的下载而不做特殊处理的话,那将会出现不可预料的后果.本文就基于ASP.NET提供大文件下载的实现思路及代 ...

  6. Django 大文件下载

    django提供文件下载时,若果文件较小,解决办法是先将要传送的内容全生成在内存中,然后再一次性传入Response对象中: def simple_file_download(request): # ...

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

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

  8. .net Mvc文件下载的功能,大文件下载完成之后修改数据库功能

    原文:.net Mvc文件下载的功能,大文件下载完成之后修改数据库功能 我服务器上文件只能下载一次,下载了之后就不能下载了,大文件或网速不好时,可能服务端文件流发送完了,客户端还没下载完,导致下载失败 ...

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

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

随机推荐

  1. 通用GPIO模拟串口,提供源代码,本人经过测试OK(第一版)

    --------------------------serial.h------------------------------------------ #ifndef _SERIAL_H_ #def ...

  2. ASCII是指128个字符(不是256个)和ASCII Extended Characters(就是那些奇怪的外文字符)

    ASCII第一次以规范标准的型态发表是在1967年,最后一次更新则是在1986年,至今为止共定义了128个字元:其中33个字元无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸.扑克牌花式等8 ...

  3. BPMN 2.0规范

    .1. BPMN 2.0是什么呢? 业务流程模型注解(Business Process Modeling Notation - BPMN)是 业务流程模型的一种标准图形注解.这个标准 是由对象管理组( ...

  4. Unity NGUI实现技能CD效果

    unity版本:4.5.1 NGUI版本:3.6.5 脚本代码:C# 在游戏中经常要实现技能的CD效果,NGUI中已经实现了这个功能,即在button上创建一个半透明的Sprite实现这个功能. 首先 ...

  5. C++ Primer 随笔 Chapter 10 关联容器

    1.关联容器的类型:map(键-值对的集合,可理解为关联数组), set(单纯的键的集合), multimap(一个键对应多个值,键唯一), multiset(相同键可以是多个). 2.pair类型提 ...

  6. vijos1082丛林探险

    P1082丛林探险 描述 东非大裂谷中有一片神秘的丛林,是全世界探险家的乐园,著名黄皮肤探险家BB一直想去试试.正好我国科学家2005年4月将首次对东非大裂谷进行科考,BB决定随科考队去神秘丛林探险. ...

  7. (转载)php数组添加、删除元素的方法

    (转载)http://www.phpgs.com/html/php/phpjichu/20120130440.html 带来一篇php 数组 添加元素.删除元素的方法的文章,有需要的php学习者参考下 ...

  8. 【宽搜】Vijos P1206 CoVH之再破难关

    题目链接: https://vijos.org/p/1206 题目大意: 给你开始和结束两张4x4的01图,每次操作只能够交换相邻的两个格子(有公共边),问最少的操作步数. 题目思路: [搜索] 这题 ...

  9. 获取Android设备屏幕分辨率

    1.Android 4.3引入的wm工具: a.获取Android设备屏幕分辨率: adb shell wm size b.获取android设备屏幕密度: adb shell wm density ...

  10. 使用Array

    public class UsingArray {     public static void output(int[]Array)     {         if(Array!=null)    ...