iOS开发网络篇—大文件的多线程断点下载(转)
iOS开发网络篇—多线程断点下载
说明:本文介绍多线程断点下载。项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件。因为实现过程较为复杂,所以下面贴出完整的代码。
实现思路:下载开始,创建一个和要下载的文件大小相同的文件(如果要下载的文件为100M,那么就在沙盒中创建一个100M的文件,然后计算每一段的下载量,开启多条线程下载各段的数据,分别写入对应的文件部分)。
项目中用到的主要类如下:
完成的实现代码如下:
主控制器中的代码:

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

自定义一个基类
YYFileDownloader.h文件

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

YYFileDownloader.m文件
1 #import "YYFileDownloader.h"
2
3 @implementation YYFileDownloader
4 @end
下载器类继承自YYFileDownloader这个类
YYFileSingDownloader.h文件

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

YYFileSingDownloader.m文件

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

设计多线程下载器(利用HMFileMultiDownloader能开启多个线程同时下载一个文件)
一个多线程下载器只下载一个文件
YYFileMultiDownloader.h文件
1 #import "YYFileDownloader.h"
2
3 @interface YYFileMultiDownloader : YYFileDownloader
4
5 @end
YYFileMultiDownloader.m文件

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

补充说明:如何获得将要下载的文件的大小?
iOS开发网络篇—大文件的多线程断点下载(转)的更多相关文章
- iOS开发网络篇—大文件的多线程断点下载
http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时 ...
- iOS开发网络请求——大文件的多线程断点下载
iOS开发中网络请求技术已经是移动app必备技术,而网络中文件传输就是其中重点了.网络文件传输对移动客户端而言主要分为文件的上传和下载.作为开发者从技术角度会将文件分为小文件和大文件.小文件因为文件大 ...
- ios开发网络学习十一:NSURLSessionDataTask离线断点下载(断点续传)
#import "ViewController.h" #define FileName @"121212.mp4" @interface ViewControl ...
- iOS开发网络篇-JSON文件的解析
一.什么是JSON数据 1.JSON的简单介绍 JSON:是一种轻量级的传输数据的格式,用于数据的交互 JSON是javascript语言的一个子集.javascript是个脚本语言(不需要编译),用 ...
- iOS开发网络篇—多线程断点下载
iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时开启多条线程下载一个较大的文件.因为实现过程较为复杂,所以下面贴出完整的代码. 实现思路:下载开始, ...
- iOS开发网络篇—文件的上传
iOS开发网络篇—文件的上传 说明:文件上传使用的时POST请求,通常把要上传的数据保存在请求体中.本文介绍如何不借助第三方框架实现iOS开发中得文件上传. 由于过程较为复杂,因此本文只贴出部分关键代 ...
- iOS开发网络篇—简单介绍ASI框架的使用
iOS开发网络篇—简单介绍ASI框架的使用 说明:本文主要介绍网络编程中常用框架ASI的简单使用. 一.ASI简单介绍 ASI:全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大 ...
- iOS开发网络篇—HTTP协议
iOS开发网络篇—HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...
- iOS开发网络篇—使用ASI框架进行文件下载
iOS开发网络篇—使用ASI框架进行文件下载 说明:本文介绍iOS网络编程中经常用到的框架ASI,如何使用该框架进行文件的下载. 一.简单介绍 代码示例: #import "YYViewCo ...
随机推荐
- 【递归】油桶问题dp
问题 : [递归]油桶问题 题目描述 楚继光扬扬得意道:“当日华山论剑,先是他用黯然销魂掌破了我的七十二路空明拳,然后我改打降龙十八掌,却不防他伸开食指和中指,竟是六脉神剑,又胜我一筹.可见天下武学彼 ...
- 借助linq2db使用Linq访问MySQL
linq2db (@github)支持Linq访问多种数据库.使用它操作MySQL非常简单,但使用方式上有一些“新奇”,特记录一下. 下载安装(@NuGet)以及使用教程(@For MySQL). 使 ...
- 配置多个Log4net实例
应用场景: 控制软件工程拆分为多个子项目,在开发阶段希望每个子项目的日志是单独的.同时又希望日志统一集中定义在Tools(Tools为工具类项目,生成Tools.dll)下,而不是分散在各个子项目中. ...
- 关于JSON的总结
本文总结自百度百科 JSON 语法规则 JSON 语法是 JavaScript 对象表示语法的子集. 数据在键值对中 数据由逗号分隔 花括号保存对象 方括号保存数组 JSON 名称/值对 JSON 数 ...
- img 元素无法获取高度的问题
项目里有这么一个功能,需要 ajax 从服务器端获取数据,然后本地生成 DOM 结构再 append 到页面上. 其中的图片是直接拿到的图像数据,而不是 url,所以据此生成 dataURI 赋值给 ...
- Bootstrap 基本用法(续)
在bootstrap中有很多的组件,这些组件可以帮组我们更快的写出一些好看的样式,下面就是一些样式: 导航框: <ul class="nav nav-tabs"> &l ...
- asp结合ajax中文乱码问题
XMLHttpRequest 在w3c标准中这样提到: 如果响应包含了为响应体指定字符编码的头部,就使用该编码.否则,假定使用 Unicode UTF-8. 前端页面sele.asp <&quo ...
- HDU4277 USACO ORZ(dfs+set)
Problem Description Like everyone, cows enjoy variety. Their current fancy is new shapes for pasture ...
- Android之所有API汇总
这里就是所有的Android API,包含所有的API类:http://www.android-doc.com/reference/packages.html
- [转]Mac OS X 下部分Android手机无法连接adb问题之解决方案
时至当今,Android山寨手机厂商已如此之多,能修改和个性化定制Android OS的能人已是多如牛毛,有的牛人修改Android系统只会影响所修改的点,不会影响其它,然后还有的就不多说了,总之做的 ...