您的位置:首页 > 理论基础 > 计算机网络

iOS多线程与网络开发之大文件下载 (边下边写/暂停恢复下载/压缩解压zip/多线程下载)

2015-08-07 21:38 731 查看

郝萌主倾心贡献,尊重作者的劳动成果,请勿转载。如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^
我要捐赠: 点击捐赠Cocos2d-X源码下载:点我传送游戏官方下载:



http://dwz.cn/RwTjl游戏视频预览:

http://dwz.cn/RzHHd游戏开发博客:

http://dwz.cn/RzJzI游戏源码传送

http://dwz.cn/Nret1

A.需求边下边写入硬盘
显示下载进度
暂停/恢复 下载
解压文件
多线程下载
B.基本知识1.小文件下载如果文件比较小,下载方式会比较多
直接用NSData的+ (id)dataWithContentsOfURL:(NSURL *)url;
利用NSURLConnection发送一个HTTP请求去下载
如果是下载图片,还可以利用SDWebImage框架 2.HTTP的Range头信息通过设置请求头Range可以指定每次从网路下载数据包的大小
Range示例
bytes=0-499 从0到499的头500个字节
bytes=500-999 从500到999的第二个500字节
bytes=500- 从500字节以后的所有字节

bytes=-500 最后500个字节
bytes=500-599,800-899 同时指定几个范围
Range小结
- 用于分隔
前面的数字表示起始字节数
后面的数组表示截止字节数,没有表示到末尾
, 用于分组,可以一次指定多个Range,不过很少用 3.第三方解压框架SSZipArchive下载地址:https://github.com/samsoffes/ssziparchive
注意:需要引入libz.dylib框架


1 // Unzipping
2 NSString *zipPath = @"path_to_your_zip_file";
3 NSString *destinationPath = @"path_to_the_folder_where_you_want_it_unzipped";
4 [SSZipArchive unzipFileAtPath:zipPath toDestination:destinationPath];
5
6 // Zipping
7 NSString *zippedPath = @"path_where_you_want_the_file_created";
8 NSArray *inputPaths = [NSArray arrayWithObjects:
9                        [[NSBundle mainBundle] pathForResource:@"photo1" ofType:@"jpg"],
10                        [[NSBundle mainBundle] pathForResource:@"photo2" ofType:@"jpg"]
11                        nil];
12 [SSZipArchive createZipFileAtPath:zippedPath withFilesAtPaths:inputPaths];




C.实现1.使用NSFileHandle实现边下边写入硬盘

1 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
2     NSLog(@"开始接收");
3
4     // 获取存放路径
5     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
6     NSString *filePath = [cachePath stringByAppendingPathComponent:@"0627.zip"];
7
8     // 创建一个空的文件,用来存放接收的数据
9     NSFileManager *manager = [NSFileManager defaultManager];
10     [manager createFileAtPath:filePath contents:nil attributes:nil];
11
12     // 把文件句柄用写入方式指向文件
13     self.handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
14
15 }
16
17 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
18     NSLog(@"正在接收: %d byte", data.length);
19
20     // 移动句柄到上次写入数据的末位置
21     [self.handle seekToEndOfFile];
22
23     // 写入数据
24     [self.handle writeData:data];
25 }


2.显示下载进度条使用ProgressView从response得到文件大小,再累加每次接收到的数据,计算出完成百分比



1 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
2     NSLog(@"开始接收");
3
4     // 获取存放路径
5     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
6     NSString *filePath = [cachePath stringByAppendingPathComponent:@"0627.zip"];
7
8     // 创建一个空的文件,用来存放接收的数据
9     NSFileManager *manager = [NSFileManager defaultManager];
10     [manager createFileAtPath:filePath contents:nil attributes:nil];
11
12     // 把文件句柄用写入方式指向文件
13     self.handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
14
15     // 复位进度条
16     self.progressView.progress = 0.0;
17
18     // 复位当前下载量
19     self.currentDataLength = 0;
20
21     // 得到总的文件大小
22     self.totalDataLength = response.expectedContentLength;
23
24
25 }
26
27 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
28     NSLog(@"正在接收: %d byte", data.length);
29     // 移动句柄到上次写入数据的末位置
30     [self.handle seekToEndOfFile];
31
32     // 写入数据
33     [self.handle writeData:data];
34
35     // 下载量累加
36     self.currentDataLength += data.length;
37
38     // 刷新进度条
39     CGFloat completedProgress = (double)self.currentDataLength / self.totalDataLength;
40     NSLog(@"completed percentage: %f%%", completedProgress * 100);
41     self.progressView.progress = completedProgress;
42 }


3.暂停/恢复下载使用成员属性标记下载状态请求得到文件头信息,根据当前下载量,设置请求request头信息,从上次下载完成的地方开始继续下载注意:NSURLConnection 取消cancel之后不能恢复,只能再创建

1 //
2 //  BigFileDownloadViewController.m
3 //  BigFileDownloadDemo
4 //
5 //  Created by haomengzhu on 15/1/26.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import "BigFileDownloadViewController.h"
10
11 @interface BigFileDownloadViewController ()
12
13 /** 进度条 */
14 @property (weak, nonatomic) IBOutlet UIProgressView *progressView;
15
16 /** 文件句柄 */
17 @property(nonatomic, strong) NSFileHandle *handle;
18
19 /** 当前完成的下载量 */
20 @property(nonatomic, assign) long long currentDataLength;
21
22 /** 总的文件大小 */
23 @property(nonatomic, assign) long long totalDataLength;
24
25 /** 当前下载连接 */
26 @property(nonatomic, strong) NSURLConnection *conn;
27
28 /** 下载状态标识 */
29 @property(nonatomic, assign, getter=isDownloading) BOOL downloading;
30
31 /** 下载/暂停 按钮事件 */
32 - (IBAction)download:(UIButton *)button;
33
34 @end
35
36 @implementation BigFileDownloadViewController
37
38 - (void)viewDidLoad {
39     [super viewDidLoad];
40     // Do any additional setup after loading the view.
41 }
42
43
44 - (IBAction)download:(UIButton *)button {
45     if (self.isDownloading) { // 如果正在下载中,暂停下载
46
47         self.downloading = NO;
48         [button setTitle:@"开始" forState:UIControlStateNormal];
49
50         //  取消连接,不能恢复
51         [self.conn cancel];
52         self.conn = nil;
53     } else { // 如果是暂停中,恢复下载
54
55         self.downloading = YES;
56         [button setTitle:@"暂停" forState:UIControlStateNormal];
57
58         // 从上次下载完成的地方继续下载,初始就是0
59         NSURL *url = [NSURL URLWithString:@"http://192.168.0.21:8080/MyTestServer/videos/0627.zip"];
60         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
61
62         // 设置request头信息,指明要从文件哪里开始下载
63         NSString *value = [NSString stringWithFormat:@"bytes=%lld-", self.currentDataLength];
64         [request setValue:value forHTTPHeaderField:@"Range"];
65
66         self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
67     }
68 }
69
70 #pragma mark - NSURLConnectionDataDelegate
71 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
72     NSLog(@"失败");
73     NSLog(@"%@", error);
74 }
75
76 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
77     NSLog(@"开始接收");
78
79     // 如果是继续下载,就不要再重复创建文件了
80     if (self.totalDataLength) return;
81
82     // 获取存放路径
83     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
84     NSString *filePath = [cachePath stringByAppendingPathComponent:@"0627.zip"];
85
86     // 创建一个空的文件,用来存放接收的数据
87     NSFileManager *manager = [NSFileManager defaultManager];
88     if ([manager fileExistsAtPath:filePath]) {
89         [manager removeItemAtPath:filePath error:nil];
90     }
91
92     // 刚创建默认是0字节
93     [manager createFileAtPath:filePath contents:nil attributes:nil];
94
95
96     // 把文件句柄用写入方式指向文件
97     self.handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
98
99     // 得到总的文件大小
100     self.totalDataLength = response.expectedContentLength;
101
102
103 }
104
105 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
106     NSLog(@"正在接收: %d byte", data.length);
107
108     // 下载量累加
109     self.currentDataLength += data.length;
110
111     // 刷新进度条
112     CGFloat completedProgress = (double)self.currentDataLength / self.totalDataLength;
113     NSLog(@"completed percentage: %f%%", completedProgress * 100);
114     self.progressView.progress = completedProgress;
115
116     // 移动句柄到上次写入数据的末位置
117     [self.handle seekToEndOfFile];
118
119     // 写入数据
120     [self.handle writeData:data];
121 }
122
123 - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
124     NSLog(@"接收完毕");
125
126     // 复位当前下载量
127     self.currentDataLength = 0;
128
129     // 复位下载文件大小
130     self.totalDataLength = 0;
131
132     // 关闭连接
133     [self.handle closeFile];
134     self.handle = nil;
135 }
136
137
138 @end


4.文件解压/压缩使用ssziparchive-master框架注意:需要引入libz.dylib框架(1)解压使用block存储下载完成后的操作:解压
1 //     完成下载后block
2     self.downloader.didFinishHandler = ^{
3         // 解压文件
4         [SSZipArchive unzipFileAtPath:filePath toDestination:cachePath];
5         NSLog(@"解压完成!");
6     };
#mark: 我使用大小为1.4G,仅包含一个视频的压缩文件进行解压,没有解出来; 解压包含了几张图片的压缩包能正常工作。 (2)压缩a.准备实验文件

b.使用SSZipArchive归档解压

1     // 获得所有png图片,注意这里是不能获得沙盒中的文件的,只能是项目中的
2     NSArray *pngs = [[NSBundle mainBundle] pathsForResourcesOfType:@"PNG" inDirectory:nil];
3     NSLog(@"%@", pngs);
4
5     // 压缩文件存放路径
6     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
7     NSString *filePath = [cachePath stringByAppendingPathComponent:@"pngs.zip"];
8
9     // 压缩文件
10     [SSZipArchive createZipFileAtPath:filePath withFilesAtPaths:pngs];
11
12     NSLog(@"压缩完成!");


5.下载器的封装将下载功能封装成一个类,传入请求url和文件存放地址,调用接口开启、暂停线程

1 //
2 //  FileDownloader.h
3 //  BigFileDownloadDemo
4 //
5 //  Created by haomengzhu on 15/1/26.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11 @interface FileDownloader : NSObject
12
13 /** 请求路径 */
14 @property(nonatomic, strong) NSURL *url;
15
16 /** 存放路径 */
17 @property(nonatomic, strong) NSString *filePath;
18
19 /** 下载状态 */
20 @property(nonatomic, readonly, getter=isDownloading) BOOL downloading;
21
22 /** 更新进度block */
23 @property(nonatomic, copy) void(^progressHandler)(double progress);
24
25 /** 完成下载后block */
26 @property(nonatomic, copy) void(^didFinishHandler)();
27
28 - (void) startDownloading;
29 - (void) pauseDownloading;
30
31 @end




1 //
2 //  FileDownloader.m
3 //  BigFileDownloadDemo
4 //
5 //  Created by haomengzhu on 15/1/26.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import "FileDownloader.h"
10 #import <UIKit/UIKit.h>
11
12 @interface FileDownloader() <NSURLConnectionDataDelegate>
13
14 /** 文件句柄 */
15 @property(nonatomic, strong) NSFileHandle *handle;
16
17 /** 当前完成的下载量 */
18 @property(nonatomic, assign) long long currentDataLength;
19
20 /** 总的文件大小 */
21 @property(nonatomic, assign) long long totalDataLength;
22
23 /** 当前下载连接 */
24 @property(nonatomic, strong) NSURLConnection *conn;
25
26 @end
27
28 @implementation FileDownloader
29
30 /** 开始下载 */
31 - (void) startDownloading {
32     _downloading = YES;
33
34     // 从上次下载完成的地方继续下载,初始就是0
35     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.url];
36
37     // 设置request头信息,指明要从文件哪里开始下载
38     NSString *value = [NSString stringWithFormat:@"bytes=%lld-", self.currentDataLength];
39     [request setValue:value forHTTPHeaderField:@"Range"];
40
41     self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
42 }
43
44 /** 暂停下载 */
45 - (void) pauseDownloading {
46     _downloading = NO;
47
48     //  取消连接,不能恢复
49     [self.conn cancel];
50     self.conn = nil;
51 }
52
53 #pragma mark - NSURLConnectionDataDelegate
54 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
55     NSLog(@"失败");
56     NSLog(@"%@", error);
57 }
58
59 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
60     NSLog(@"开始接收");
61
62     // 如果是继续下载,就不要再重复创建文件了
63     if (self.totalDataLength) return;
64
65     // 创建一个空的文件,用来存放接收的数据
66     NSFileManager *manager = [NSFileManager defaultManager];
67     if ([manager fileExistsAtPath:self.filePath]) {
68         [manager removeItemAtPath:self.filePath error:nil];
69     }
70
71     // 刚创建默认是0字节
72     [manager createFileAtPath:self.filePath contents:nil attributes:nil];
73
74
75     // 把文件句柄用写入方式指向文件
76     self.handle = [NSFileHandle fileHandleForWritingAtPath:self.filePath];
77
78     // 得到总的文件大小
79     self.totalDataLength = response.expectedContentLength;
80
81
82 }
83
84 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
85     NSLog(@"正在接收: %d byte", data.length);
86
87     // 下载量累加
88     self.currentDataLength += data.length;
89
90     // 刷新进度条
91     CGFloat completedProgress = (double)self.currentDataLength / self.totalDataLength;
92     NSLog(@"completed percentage: %f%%", completedProgress * 100);
93     if (self.progressHandler) {
94         self.progressHandler(completedProgress);
95     }
96
97     // 移动句柄到上次写入数据的末位置
98     [self.handle seekToEndOfFile];
99
100     // 写入数据
101     [self.handle writeData:data];
102
103     NSLog(@"现在的线程:%@", [NSThread currentThread]);
104 }
105
106 - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
107     NSLog(@"接收完毕");
108
109     // 复位当前下载量
110     self.currentDataLength = 0;
111
112     // 复位下载文件大小
113     self.totalDataLength = 0;
114
115     // 关闭连接
116     [self.handle closeFile];
117     self.handle = nil;
118
119     if (self.didFinishHandler) {
120         self.didFinishHandler();
121     }
122 }
123
124 @end




1 //
2 //  BigFileDownloadViewController.m
3 //  BigFileDownloadDemo
4 //
5 //  Created by haomengzhu on 15/1/26.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import "BigFileDownloadViewController.h"
10 #import "FileDownloader.h"
11 #import "SSZipArchive.h"
12
13 @interface BigFileDownloadViewController ()
14
15 /** 进度条 */
16 @property (weak, nonatomic) IBOutlet UIProgressView *progressView;
17
18 /** 下载器 */
19 @property(nonatomic, strong) FileDownloader *downloader;
20
21 /** 下载/暂停 按钮事件 */
22 - (IBAction)download:(UIButton *)button;
23
24 @end
25
26 @implementation BigFileDownloadViewController
27
28 - (void)viewDidLoad {
29     [super viewDidLoad];
30     // Do any additional setup after loading the view.
31
32     // 设置下载器请求路径
33     self.downloader = [[FileDownloader alloc] init];
34     self.downloader.url = [NSURL URLWithString:@"http://192.168.0.21:8080/MyTestServer/videos/0627.zip"];
35 //    self.downloader.url = [NSURL URLWithString:@"http://192.168.0.21:8080/MyTestServer/images/images.zip"];
36
37     // 设置存放路径
38     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
39     NSString *filePath = [cachePath stringByAppendingPathComponent:@"0627.zip"];
40 //    NSString *filePath = [cachePath stringByAppendingPathComponent:@"images.zip"];
41     self.downloader.filePath = filePath;
42
43
44     // 刷新进度条的block
45     typeof(self) vc = self;
46     self.downloader.progressHandler = ^(double progress) {
47         vc.progressView.progress = progress;
48     };
49
50 //     完成下载后block
51     self.downloader.didFinishHandler = ^{
52         // 解压文件
53         [SSZipArchive unzipFileAtPath:filePath toDestination:cachePath];
54         NSLog(@"解压完成!");
55     };
56 }
57
58
59 - (IBAction)download:(UIButton *)button {
60     if (self.downloader.isDownloading) { // 如果正在下载中,暂停下载
61         [button setTitle:@"开始" forState:UIControlStateNormal];
62         [self.downloader pauseDownloading];
63     } else { // 如果是暂停中,恢复下载
64         [button setTitle:@"暂停" forState:UIControlStateNormal];
65         [self.downloader startDownloading];
66     }
67 }
68
69
70 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
71
72     // 获得所有png图片
73     NSArray *pngs = [[NSBundle mainBundle] pathsForResourcesOfType:@"PNG" inDirectory:nil];
74     NSLog(@"%@", pngs);
75
76     // 压缩文件存放路径
77     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
78     NSString *filePath = [cachePath stringByAppendingPathComponent:@"pngs.zip"];
79
80     // 压缩文件
81     [SSZipArchive createZipFileAtPath:filePath withFilesAtPaths:pngs];
82
83     NSLog(@"压缩完成!");
84 }
85
86 @end


6.多线程下载思路:由于调用NSURLConnection的代理方法进行服务器请求和接收,发送的是异步请求,所以可以认为利用几个NSURLConnection同时发送请求,下载一个文件的不同部分,就能实现多线程下载。 创建多线下载器类和单线下载器
多线下载器对象创建n个单线下载器来进行下载
创建一个跟实际文件大小一样的临时文件,用来辅助定位单线下载器的下载存储位置
n个单线下载器负责一个文件的不同部分的下载
使用请求头设置Range来实现文件下载部分的不同


(1)基本下载器用来声明了一些公用属性和方法

1 //
2 //  FileDownloader.h
3 //  BigFileDownloadDemo
4 //
5 //  Created by haomengzhu on 15/1/26.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11 @interface FileDownloader : NSObject
12 {
13     @protected
14     BOOL _downloading;
15 }
16
17 /** 请求路径 */
18 @property(nonatomic, strong) NSString *url;
19
20 /** 存放路径 */
21 @property(nonatomic, strong) NSString *filePath;
22
23 /** 下载状态 */
24 @property(nonatomic, readonly, getter=isDownloading) BOOL downloading;
25
26 /** 更新进度block */
27 @property(nonatomic, copy) void(^progressHandler)(double progress);
28
29 /** 完成下载后block */
30 @property(nonatomic, copy) void(^didFinishHandler)();
31
32 - (void) startDownloading;
33 - (void) pauseDownloading;
34
35 @end


(2)单线下载器

1 //
2 //  SingleDownloader.h
3 //  MultiDownloaderDemo
4 //
5 //  Created by haomengzhu on 15/1/27.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import "FileDownloader.h"
10
11 @interface SingleDownloader : FileDownloader
12
13 /** 开始下载的位置(字节) */
14 @property(nonatomic, assign) long long begin;
15
16 /** 结束下载的位置(字节) */
17 @property(nonatomic, assign) long long end;
18
19 @end




1 //
2 //  SingleDownloader.m
3 //  MultiDownloaderDemo
4 //
5 //  Created by haomengzhu on 15/1/27.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import "SingleDownloader.h"
10
11 @interface SingleDownloader() <NSURLConnectionDataDelegate>
12
13 /** 文件句柄 */
14 @property(nonatomic, strong) NSFileHandle *handle;
15
16 /** 当前下载连接 */
17 @property(nonatomic, strong) NSURLConnection *conn;
18
19 /** 当前下载量 */
20 @property(nonatomic, assign) long long currentLength;
21
22 @end
23
24 @implementation SingleDownloader
25
26 /** 初始化文件句柄 */
27 - (NSFileHandle *)handle {
28     if (nil == _handle) {
29         _handle = [NSFileHandle fileHandleForWritingAtPath:self.filePath];
30     }
31     return _handle;
32 }
33
34 /** 开始下载 */
35 - (void) startDownloading {
36     // 从上次下载完成的地方继续下载,初始就是0
37     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url]];
38
39     // 设置request头信息,指明要从文件哪里开始下载
40     NSString *value = [NSString stringWithFormat:@"bytes=%lld-%lld", self.begin, self.end];
41     [request setValue:value forHTTPHeaderField:@"Range"];
42
43     self.conn = [NSURLConnection connectionWithRequest:request delegate:self];
44
45     _downloading = YES;
46 }
47
48 /** 暂停下载 */
49 - (void) pauseDownloading {
50     //  取消连接,不能恢复
51     [self.conn cancel];
52     self.conn = nil;
53
54     _downloading = NO;
55 }
56
57 #pragma mark - NSURLConnectionDataDelegate
58 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
59     NSLog(@"失败");
60     NSLog(@"%@", error);
61 }
62
63 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
64     NSLog(@"开始接收");
65 }
66
67 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
68     // 移动句柄到上次写入数据的末位置
69     [self.handle seekToFileOffset:self.begin + self.currentLength];
70
71     // 写入数据
72     [self.handle writeData:data];
73
74     // 已经下载的量
75     self.currentLength += data.length;
76
77     if (self.progressHandler) {
78         double progress = (double)self.currentLength / (self.end - self.begin + 1);
79         self.progressHandler(progress);
80     }
81 }
82
83 - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
84     NSLog(@"接收完毕");
85
86     // 清空下载量
87     self.currentLength = 0;
88
89
90     // 关闭连接
91     [self.handle closeFile];
92     self.handle = nil;
93
94     if (self.didFinishHandler) {
95         self.didFinishHandler();
96     }
97 }
98
99
100 @end


(3)总下载器

1 //
2 //  MultiDownloader.h
3 //  MultiDownloaderDemo
4 //
5 //  Created by haomengzhu on 15/1/27.
6 //  Copyright (c) 2015年 haomengzhu. All rights reserved.
7 //
8
9 #import "FileDownloader.h"
10
11 @interface MultiDownloader : FileDownloader
12
13 @end
14
15 //
16 //  MultiDownloader.m
17 //  MultiDownloaderDemo
18 //
19 //  Created by hellovoidworld on 15/1/27.
20 //  Copyright (c) 2015年 hellovoidworld. All rights reserved.
21 //
22
23 #import "MultiDownloader.h"
24 #import "SingleDownloader.h"
25
26 #define MaxMultilineCount 4
27
28 @interface MultiDownloader()
29
30 @property(nonatomic, strong) NSMutableArray *singleDownloaders;
31
32 @end
33
34 @implementation MultiDownloader
35
36 /** 初始化单线下载器 */
37 - (NSMutableArray *)singleDownloaders {
38     if (!_singleDownloaders) {
39         _singleDownloaders = [NSMutableArray array];
40
41         long long fileSize = [self getFileSize];
42         long long singleFileSize = 0; // 每条子线下载量
43         if (fileSize % MaxMultilineCount == 0) {
44             singleFileSize = fileSize / MaxMultilineCount;
45         } else {
46             singleFileSize = fileSize / MaxMultilineCount + 1;
47         }
48
49         for (int i=0; i<MaxMultilineCount; i++) {
50             SingleDownloader *downloader = [[SingleDownloader alloc] init];
51             downloader.url = self.url;
52             downloader.filePath = self.filePath;
53             downloader.begin = i * singleFileSize;
54             downloader.end = downloader.begin + singleFileSize - 1;
55             downloader.progressHandler = ^(double progress){
56                 NSLog(@"%d号单线下载器正在下载,下载进度:%f", i, progress);
57             };
58
59             [self.singleDownloaders addObject:downloader];
60         }
61
62         // 创建临时文件,文件大小要跟实际大小一致
63         // 1.创建一个0字节文件
64         [[NSFileManager defaultManager] createFileAtPath:self.filePath contents:nil attributes:nil];
65
66         // 2.指定文件大小
67         NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.filePath];
68         [fileHandle truncateFileAtOffset:fileSize];
69     }
70
71     return _singleDownloaders;
72 }
73
74 /** 获得文件大小 */
75 - (long long) getFileSize {
76     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.url]];
77     request.HTTPMethod = @"HEAD";// 请求得到头响应
78
79     NSURLResponse *response = nil;
80     [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
81     return response.expectedContentLength;
82 }
83
84 /** 开始下载 */
85 - (void)startDownloading {
86     [self.singleDownloaders makeObjectsPerformSelector:@selector(startDownloading)];
87     _downloading = YES;
88     NSLog(@"多线程下载开始");
89 }
90
91 /** 暂停下载 */
92 - (void)pauseDownloading {
93     [self.singleDownloaders makeObjectsPerformSelector:@selector(pauseDownloading)];
94     _downloading = NO;
95     NSLog(@"多线程下载暂停!");
96 }
97
98 @end
99
100 (4)控制器调用
101 - (IBAction)startDownloading {
102     MultiDownloader *downloader = [[MultiDownloader alloc] init];
103     downloader.url = @"http://192.168.0.21:8080/MyTestServer/videos/0627.zip";
104
105     // 设置存放路径
106     NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
107     downloader.filePath = [cachePath stringByAppendingPathComponent:@"0627.zip"];
108
109     // 开始下载
110     [downloader startDownloading];
111 }


郝萌主倾心贡献,尊重作者的劳动成果,请勿转载。如果文章对您有所帮助,欢迎给作者捐赠,支持郝萌主,捐赠数额随意,重在心意^_^
我要捐赠: 点击捐赠Cocos2d-X源码下载:点我传送游戏官方下载:



http://dwz.cn/RwTjl游戏视频预览:

http://dwz.cn/RzHHd游戏开发博客:

http://dwz.cn/RzJzI游戏源码传送

http://dwz.cn/Nret1

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息