iOS开发网络篇—多线程断点下载

说明:本文介绍多线程断点下载。项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件。因为实现过程较为复杂,所以下面贴出完整的代码。

实现思路:下载开始,创建一个和要下载的文件大小相同的文件(如果要下载的文件为100M,那么就在沙盒中创建一个100M的文件,然后计算每一段的下载量,开启多条线程下载各段的数据,分别写入对应的文件部分)。

项目中用到的主要类如下:

完成的实现代码如下:

主控制器中的代码:

  1. 1 #import "YYViewController.h"
  2. 2 #import "YYFileMultiDownloader.h"
  3. 3
  4. 4 @interface YYViewController ()
  5. 5 @property (nonatomic, strong) YYFileMultiDownloader *fileMultiDownloader;
  6. 6 @end
  7. 7
  8. 8 @implementation YYViewController
  9. 9 - (YYFileMultiDownloader *)fileMultiDownloader
  10. 10 {
  11. 11 if (!_fileMultiDownloader) {
  12. 12 _fileMultiDownloader = [[YYFileMultiDownloader alloc] init];
  13. 13 // 需要下载的文件远程URL
  14. 14 _fileMultiDownloader.url = @"http://192.168.1.200:8080/MJServer/resources/jre.zip";
  15. 15 // 文件保存到什么地方
  16. 16 NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
  17. 17 NSString *filepath = [caches stringByAppendingPathComponent:@"jre.zip"];
  18. 18 _fileMultiDownloader.destPath = filepath;
  19. 19 }
  20. 20 return _fileMultiDownloader;
  21. 21 }
  22. 22
  23. 23 - (void)viewDidLoad
  24. 24 {
  25. 25 [super viewDidLoad];
  26. 26
  27. 27 }
  28. 28
  29. 29 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
  30. 30 {
  31. 31 [self.fileMultiDownloader start];
  32. 32 }
  33. 33
  34. 34 @end

自定义一个基类

YYFileDownloader.h文件

  1. 1 #import <Foundation/Foundation.h>
  2. 2
  3. 3 @interface YYFileDownloader : NSObject
  4. 4 {
  5. 5 BOOL _downloading;
  6. 6 }
  7. 7 /**
  8. 8 * 所需要下载文件的远程URL(连接服务器的路径)
  9. 9 */
  10. 10 @property (nonatomic, copy) NSString *url;
  11. 11 /**
  12. 12 * 文件的存储路径(文件下载到什么地方)
  13. 13 */
  14. 14 @property (nonatomic, copy) NSString *destPath;
  15. 15
  16. 16 /**
  17. 17 * 是否正在下载(有没有在下载, 只有下载器内部才知道)
  18. 18 */
  19. 19 @property (nonatomic, readonly, getter = isDownloading) BOOL downloading;
  20. 20
  21. 21 /**
  22. 22 * 用来监听下载进度
  23. 23 */
  24. 24 @property (nonatomic, copy) void (^progressHandler)(double progress);
  25. 25
  26. 26 /**
  27. 27 * 开始(恢复)下载
  28. 28 */
  29. 29 - (void)start;
  30. 30
  31. 31 /**
  32. 32 * 暂停下载
  33. 33 */
  34. 34 - (void)pause;
  35. 35 @end

YYFileDownloader.m文件

  1. 1 #import "YYFileDownloader.h"
  2. 2
  3. 3 @implementation YYFileDownloader
  4. 4 @end

下载器类继承自YYFileDownloader这个类

YYFileSingDownloader.h文件

  1. 1 #import "YYFileDownloader.h"
  2. 2
  3. 3 @interface YYFileSingleDownloader : YYFileDownloader
  4. 4 /**
  5. 5 * 开始的位置
  6. 6 */
  7. 7 @property (nonatomic, assign) long long begin;
  8. 8 /**
  9. 9 * 结束的位置
  10. 10 */
  11. 11 @property (nonatomic, assign) long long end;
  12. 12 @end

YYFileSingDownloader.m文件

  1. 1 #import "YYFileSingleDownloader.h"
  2. 2 @interface YYFileSingleDownloader() <NSURLConnectionDataDelegate>
  3. 3 /**
  4. 4 * 连接对象
  5. 5 */
  6. 6 @property (nonatomic, strong) NSURLConnection *conn;
  7. 7
  8. 8 /**
  9. 9 * 写数据的文件句柄
  10. 10 */
  11. 11 @property (nonatomic, strong) NSFileHandle *writeHandle;
  12. 12 /**
  13. 13 * 当前已下载数据的长度
  14. 14 */
  15. 15 @property (nonatomic, assign) long long currentLength;
  16. 16 @end
  17. 17
  18. 18 @implementation YYFileSingleDownloader
  19. 19
  20. 20 - (NSFileHandle *)writeHandle
  21. 21 {
  22. 22 if (!_writeHandle) {
  23. 23 _writeHandle = [NSFileHandle fileHandleForWritingAtPath:self.destPath];
  24. 24 }
  25. 25 return _writeHandle;
  26. 26 }
  27. 27
  28. 28 /**
  29. 29 * 开始(恢复)下载
  30. 30 */
  31. 31 - (void)start
  32. 32 {
  33. 33 NSURL *url = [NSURL URLWithString:self.url];
  34. 34 // 默认就是GET请求
  35. 35 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  36. 36 // 设置请求头信息
  37. 37 NSString *value = [NSString stringWithFormat:@"bytes=%lld-%lld", self.begin + self.currentLength, self.end];
  38. 38 [request setValue:value forHTTPHeaderField:@"Range"];
  39. 39 self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
  40. 40
  41. 41 _downloading = YES;
  42. 42 }
  43. 43
  44. 44 /**
  45. 45 * 暂停下载
  46. 46 */
  47. 47 - (void)pause
  48. 48 {
  49. 49 [self.conn cancel];
  50. 50 self.conn = nil;
  51. 51
  52. 52 _downloading = NO;
  53. 53 }
  54. 54
  55. 55
  56. 56 #pragma mark - NSURLConnectionDataDelegate 代理方法
  57. 57 /**
  58. 58 * 1. 当接受到服务器的响应(连通了服务器)就会调用
  59. 59 */
  60. 60 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
  61. 61 {
  62. 62
  63. 63 }
  64. 64
  65. 65 /**
  66. 66 * 2. 当接受到服务器的数据就会调用(可能会被调用多次, 每次调用只会传递部分数据)
  67. 67 */
  68. 68 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
  69. 69 {
  70. 70 // 移动到文件的尾部
  71. 71 [self.writeHandle seekToFileOffset:self.begin + self.currentLength];
  72. 72 // 从当前移动的位置(文件尾部)开始写入数据
  73. 73 [self.writeHandle writeData:data];
  74. 74
  75. 75 // 累加长度
  76. 76 self.currentLength += data.length;
  77. 77
  78. 78 // 打印下载进度
  79. 79 double progress = (double)self.currentLength / (self.end - self.begin);
  80. 80 if (self.progressHandler) {
  81. 81 self.progressHandler(progress);
  82. 82 }
  83. 83 }
  84. 84
  85. 85 /**
  86. 86 * 3. 当服务器的数据接受完毕后就会调用
  87. 87 */
  88. 88 - (void)connectionDidFinishLoading:(NSURLConnection *)connection
  89. 89 {
  90. 90 // 清空属性值
  91. 91 self.currentLength = 0;
  92. 92
  93. 93 // 关闭连接(不再输入数据到文件中)
  94. 94 [self.writeHandle closeFile];
  95. 95 self.writeHandle = nil;
  96. 96 }
  97. 97
  98. 98 /**
  99. 99 * 请求错误(失败)的时候调用(请求超时\断网\没有网, 一般指客户端错误)
  100. 100 */
  101. 101 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
  102. 102 {
  103. 103
  104. 104 }
  105. 105
  106. 106 @end

设计多线程下载器(利用HMFileMultiDownloader能开启多个线程同时下载一个文件)

一个多线程下载器只下载一个文件

YYFileMultiDownloader.h文件

  1. 1 #import "YYFileDownloader.h"
  2. 2
  3. 3 @interface YYFileMultiDownloader : YYFileDownloader
  4. 4
  5. 5 @end

YYFileMultiDownloader.m文件

  1. 1 #import "YYFileMultiDownloader.h"
  2. 2 #import "YYFileSingleDownloader.h"
  3. 3
  4. 4 #define YYMaxDownloadCount 4
  5. 5
  6. 6 @interface YYFileMultiDownloader()
  7. 7 @property (nonatomic, strong) NSMutableArray *singleDownloaders;
  8. 8 @property (nonatomic, assign) long long totalLength;
  9. 9 @end
  10. 10
  11. 11 @implementation YYFileMultiDownloader
  12. 12
  13. 13 - (void)getFilesize
  14. 14 {
  15. 15 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url]];
  16. 16 request.HTTPMethod = @"HEAD";
  17. 17
  18. 18 NSURLResponse *response = nil;
  19. 19 #warning 这里要用异步请求
  20. 20 [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
  21. 21 self.totalLength = response.expectedContentLength;
  22. 22 }
  23. 23
  24. 24 - (NSMutableArray *)singleDownloaders
  25. 25 {
  26. 26 if (!_singleDownloaders) {
  27. 27 _singleDownloaders = [NSMutableArray array];
  28. 28
  29. 29 // 获得文件大小
  30. 30 [self getFilesize];
  31. 31
  32. 32 // 每条路径的下载量
  33. 33 long long size = 0;
  34. 34 if (self.totalLength % YYMaxDownloadCount == 0) {
  35. 35 size = self.totalLength / YYMaxDownloadCount;
  36. 36 } else {
  37. 37 size = self.totalLength / YYMaxDownloadCount + 1;
  38. 38 }
  39. 39
  40. 40 // 创建N个下载器
  41. 41 for (int i = 0; i<YYMaxDownloadCount; i++) {
  42. 42 YYFileSingleDownloader *singleDownloader = [[YYFileSingleDownloader alloc] init];
  43. 43 singleDownloader.url = self.url;
  44. 44 singleDownloader.destPath = self.destPath;
  45. 45 singleDownloader.begin = i * size;
  46. 46 singleDownloader.end = singleDownloader.begin + size - 1;
  47. 47 singleDownloader.progressHandler = ^(double progress){
  48. 48 NSLog(@"%d --- %f", i, progress);
  49. 49 };
  50. 50 [_singleDownloaders addObject:singleDownloader];
  51. 51 }
  52. 52
  53. 53 // 创建一个跟服务器文件等大小的临时文件
  54. 54 [[NSFileManager defaultManager] createFileAtPath:self.destPath contents:nil attributes:nil];
  55. 55
  56. 56 // 让self.destPath文件的长度是self.totalLengt
  57. 57 NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.destPath];
  58. 58 [handle truncateFileAtOffset:self.totalLength];
  59. 59 }
  60. 60 return _singleDownloaders;
  61. 61 }
  62. 62
  63. 63 /**
  64. 64 * 开始(恢复)下载
  65. 65 */
  66. 66 - (void)start
  67. 67 {
  68. 68 [self.singleDownloaders makeObjectsPerformSelector:@selector(start)];
  69. 69
  70. 70 _downloading = YES;
  71. 71 }
  72. 72
  73. 73 /**
  74. 74 * 暂停下载
  75. 75 */
  76. 76 - (void)pause
  77. 77 {
  78. 78 [self.singleDownloaders makeObjectsPerformSelector:@selector(pause)];
  79. 79 _downloading = NO;
  80. 80 }
  81. 81
  82. 82 @end

补充说明:如何获得将要下载的文件的大小?

 
 
标签: IOS开发网络篇

iOS开发网络篇—大文件的多线程断点下载(转)的更多相关文章

  1. iOS开发网络篇—大文件的多线程断点下载

    http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时 ...

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

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

  3. ios开发网络学习十一:NSURLSessionDataTask离线断点下载(断点续传)

    #import "ViewController.h" #define FileName @"121212.mp4" @interface ViewControl ...

  4. iOS开发网络篇-JSON文件的解析

    一.什么是JSON数据 1.JSON的简单介绍 JSON:是一种轻量级的传输数据的格式,用于数据的交互 JSON是javascript语言的一个子集.javascript是个脚本语言(不需要编译),用 ...

  5. iOS开发网络篇—多线程断点下载

    iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始, ...

  6. iOS开发网络篇—文件的上传

    iOS开发网络篇—文件的上传 说明:文件上传使用的时POST请求,通常把要上传的数据保存在请求体中.本文介绍如何不借助第三方框架实现iOS开发中得文件上传. 由于过程较为复杂,因此本文只贴出部分关键代 ...

  7. iOS开发网络篇—简单介绍ASI框架的使用

    iOS开发网络篇—简单介绍ASI框架的使用 说明:本文主要介绍网络编程中常用框架ASI的简单使用. 一.ASI简单介绍 ASI:全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大 ...

  8. iOS开发网络篇—HTTP协议

    iOS开发网络篇—HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...

  9. iOS开发网络篇—使用ASI框架进行文件下载

    iOS开发网络篇—使用ASI框架进行文件下载 说明:本文介绍iOS网络编程中经常用到的框架ASI,如何使用该框架进行文件的下载. 一.简单介绍 代码示例: #import "YYViewCo ...

随机推荐

  1. 用pf透明地将流量从一台机器转到另一台机器上的缘起及实现方式对比

    下面是也是我在12580工作时发生的事情,重新记录并发出来.这种特殊需求很考 验PF的功底.在新旧系统并存,做重构的时候有时很需要这种救急的作法.一.缘起miscweb1(172.16.88.228) ...

  2. JAVA备忘录

    本文主要是记录一下JAVA: 1.Arrays.的几个用法: fill:数组全部置一个数 sort:排序 binarySearch:二分查找 2.Map的用法: Map<Integer,Inte ...

  3. Sharepoint 2013 系列篇(安装部署)--上篇

    前言 sharepoint的部署是按照物理拓扑图的架构来部署,按照物理拓扑图架构分为一层拓扑图架构,二层拓扑图架构,三层拓扑图架构,多层拓扑图架构. 按照分层的拓扑图部署是按照需求来划分的,一层拓扑图 ...

  4. Java中的堆和栈的区别

    当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先 ...

  5. ubuntn14.04 32位安装hadoop2.7.2

    1. 创建用户一枚, sudo addgroup hadoop sudo adduser -ingroup hadoop hadoop_lcc 2. 为新创建的用户添加sudo权限 sudo gedi ...

  6. 自定义View(二)ViewPage广告轮播

    自定义View的第二个学习案例,使用ViewPage实现广告轮播,通过组合现有的View实现效果如下: 有关ViewPage使用可以学习谷歌官方API,和训练案例: 1.使用ViewPage实现屏幕滑 ...

  7. Part 2 How are the URL's mapped to Controller Action Methods?

    Part 2 How are the URL's mapped to Controller Action Methods? The answer is ASP.NET Routing.Notice t ...

  8. 关于近期需要学习sqlserver2008

    在胜利油田物探院借了一本书叫做 sqlserver2008宝典 第二版,但是看不下去 下面打算直接安装数据库上手了,边练边学

  9. 15条JavaScript最佳实践很经典噢

    感觉比较经典,特转载腾讯大讲堂.本文档整理大部分公认的.或者少有争议的JavaScript良好书写规范(Best Practice).一些显而易见的常识就不再论述(比如要用对象支持识别判断,而不是浏览 ...

  10. vpn连接成功后,本地无法连接外网

    把在远程网络上使用默认网关前面的对勾取消掉,确定就ok啦...