一、简单说明
1.思路

把下载的data追加到文件的尾部,直到所有的数据下载完为止。
1.在连通了服务器的时候,创建一个空的文件到沙盒中NSFileManager(文件管理类)
2.创建写数据的文件句柄
3.在接收到服务器返回的数据后,把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖)
3.1移动到文件的尾部
3.2从当前移动的位置,写入数据
4.服务器的数据加载完毕后关闭连接,不再输入数据在文件中
二、代码示例
1.代码:
新建一个类,让其继承自NSObject类,一个文件下载器只下载一个文件。
自定义类的TXFileDownloader.h代码:
1 // 2 // TXFileDownloader.h 3 // 文件下载 4 // 5 // Created by 鑫 on 14/12/23. 6 // Copyright (c) 2014年 梁镋鑫. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface TXFileDownloader : NSObject 12 //下载的远程url(连接到服务器的路径) 13 @property(nonatomic,strong)NSString *url; 14 //下载后的存储路径(文件下载到什么地方) 15 @property(nonatomic,strong)NSString *destPath; 16 //是否正在下载(只有下载器内部清楚) 17 @property(nonatomic,readonly,getter = isDownloading)BOOL Downloading; 18 //用来监听下载进度 19 @property(nonatomic,copy)void (^progressHandler)(double progress); 20 //用来监听下载完成 21 @property(nonatomic,copy)void (^completionHandler)(); 22 //用来监听下载错误 23 @property(nonatomic,copy)void(^failureHandler)(NSError *error); 24 -(void)pause; 25 -(void)start; 26 @end
自定义类的TXFileDownloader.m

1 // TXFileDownloader.m
2 // 文件下载
3 //
4 // Created by 鑫 on 14/12/23.
5 // Copyright (c) 2014年 梁镋鑫. All rights reserved.
6 //
7
8 #import "TXFileDownloader.h"
9 @interface TXFileDownloader ()<NSURLConnectionDataDelegate>
10 //请求对象
11 @property(nonatomic,strong)NSURLConnection *cnnt;
12 //文件句柄
13 @property(nonatomic,strong)NSFileHandle *writeHandle;
14 //当前获取到的数据长度
15 @property(nonatomic,assign)long long currentLength;
16 //完整数据长度
17 @property(nonatomic,assign)long long sumLength;
18 @end
19
20 @implementation TXFileDownloader
21 //开始下载
22 -(void)start
23 {
24 _Downloading=YES;
25
26 //创建一个请求
27 NSURL *URL=[NSURL URLWithString:self.url];
28 NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:URL];
29
30 //设置请求头信息
31 //self.currentLength字节部分重新开始读取
32 NSString *value=[NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
33 [request setValue:value forHTTPHeaderField:@"Range"];
34
35 //发送请求(使用代理的方式)
36 self.cnnt=[NSURLConnection connectionWithRequest:request delegate:self];
37
38 }
39
40 //暂停下载
41 -(void)pause
42 {
43 _Downloading=NO;
44 //取消发送请求
45 [self.cnnt cancel];
46 self.cnnt=nil;
47 }
48
49 #pragma mark- NSURLConnectionDataDelegate代理方法
50 /*
51 *当接收到服务器的响应(连通了服务器)时会调用
52 */
53 -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
54 {
55 #warning 判断是否是第一次连接
56 if (self.sumLength) return;
57
58 //1.创建文件存数路径
59 NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
60 NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"];
61
62
63
64 //2.创建一个空的文件,到沙盒中
65 NSFileManager *mgr=[NSFileManager defaultManager];
66 //刚创建完毕的大小是o字节
67 [mgr createFileAtPath:filePath contents:nil attributes:nil];
68
69 //3.创建写数据的文件句柄
70 self.writeHandle=[NSFileHandle fileHandleForWritingAtPath:filePath];
71
72 //4.获取完整的文件长度
73 self.sumLength=response.expectedContentLength;
74 }
75
76 /*
77 *当接收到服务器的数据时会调用(可能会被调用多次,每次只传递部分数据)
78 */
79 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
80 {
81 //累加接收到的数据长度
82 self.currentLength+=data.length;
83 //计算进度值
84 double progress=(double)self.currentLength/self.sumLength;
85 // self.progress.progress=progress;
86 if (self.progressHandler) {//传递进度值给block
87 self.progressHandler(progress);
88
89 //相当于在此处调用了下面的代码
90 // ^(double progress)
91 // {
92 // //把进度的值,传递到控制器中进度条,以进行显示
93 // vc.progress.progress=progress;
94 // };
95 }
96
97
98 //一点一点接收数据。
99 NSLog(@"接收到服务器的数据!---%d",data.length);
100 //把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖)
101 //移动到文件的尾部
102 [self.writeHandle seekToEndOfFile];
103 //从当前移动的位置,写入数据
104 [self.writeHandle writeData:data];
105 }
106
107 /*
108 *当服务器的数据加载完毕时就会调用
109 */
110 -(void)connectionDidFinishLoading:(NSURLConnection *)connection
111 {
112 NSLog(@"下载完毕----%lld",self.sumLength);
113 //关闭连接,不再输入数据在文件中
114 [self.writeHandle closeFile];
115 self.writeHandle=nil;
116
117 //清空进度值
118 self.currentLength=0;
119 self.sumLength=0;
120
121 if (self.completionHandler) {//下载完成通知控制器
122 self.completionHandler();
123 //相当于下面的代码
124 // ^{
125 // NSLog(@"下载完成");
126 // [self.btn setTitle:@"下载已经完成" forState:UIControlStateNormal];
127 // }
128 }
129
130 }
131 /*
132 *请求错误(失败)的时候调用(请求超时\断网\没有网\,一般指客户端错误)
133 */
134 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
135 {
136 if (self.failureHandler) {//通知控制器,下载出错
137 self.failureHandler(error);
138 //相当于调用了下面的代码
139 // ^{
140 // NSLog(@"下载错误!");
141 // }
142 }
143 }
144
145 @end
实现代码:
主控制器TXViewController.m

1 //
2 // TXViewController.m
3 // 文件下载
4 //
5 // Created by 鑫 on 14/12/23.
6 // Copyright (c) 2014年 梁镋鑫. All rights reserved.
7 //
8
9 #import "TXViewController.h"
10 #import "TXFileDownloader.h"
11 @interface TXViewController ()
12
13
14 @property(nonatomic,strong)TXFileDownloader *fileDownloader;
15 @property (weak, nonatomic) IBOutlet UIButton *btn;
16 @property (weak, nonatomic) IBOutlet UIProgressView *progress;
17 @end
18
19 @implementation TXViewController
20
21 - (void)viewDidLoad
22 {
23 [super viewDidLoad];
24 }
25
26 #pragma mark-懒加载
27 -(TXFileDownloader *)fileDownloader
28 {
29 if (_fileDownloader==nil) {
30 _fileDownloader=[[TXFileDownloader alloc]init];
31 //设置文件下载路径
32 _fileDownloader.url=@"http://192.168.1.53:8080/MJServer/resources/video.zip";
33
34 //设置文件保存路径
35 NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
36 NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"];
37 _fileDownloader.destPath=filePath;
38
39 //获取10的真实类型,把它作为a的类型
40 // typeof(10) a = 20; // int a = 20;
41 __weak typeof(self) vc=self;
42 _fileDownloader.progressHandler=^(double progress)
43 {
44 vc.progress.progress=progress;
45 NSLog(@"%f",progress);
46 };
47 _fileDownloader.completionHandler=^{
48 NSLog(@"下载完成");
49 [vc.btn setTitle:@"下载已经完成" forState:UIControlStateNormal];
50 };
51 _fileDownloader.failureHandler=^(NSError *error){
52 NSLog(@"下载错误!%@",error);
53 };
54 }
55 return _fileDownloader;
56 }
57
58 //点击下载按钮,处理操作
59 - (IBAction)star {
60 if (self.fileDownloader.isDownloading) {//如果正在下载,那么调用方法暂停
61 [self.fileDownloader pause];
62 [self.btn setTitle:@"暂停" forState:UIControlStateNormal];
63 }else//如果没有正在下载,那么调用下载方法
64 {
65 [self.fileDownloader start];
66 [self.btn setTitle:@"下载" forState:UIControlStateNormal];
67 }
68 }
69
70 @end
代码:
控制器想监听下载器的下载进度,控制器想监听下载器的下载完毕,控制器想监听下载器的下载失败等都可以使用block的方式进行。
打印查看:

2.代码说明
(1)创建文件存储路径(写入到沙盒)
NSString *caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath=[caches stringByAppendingPathComponent:@"video.zip"];
(2)创建一个空的文件夹( NSFileManager类的使用)
NSFileManager *mgr=[NSFileManager defaultManager];
(3)创建写数据的文件句柄
self.writeHandle=[NSFileHandle fileHandleForWritingAtPath:filePath];
(4)把data写入到创建的空文件中,但是不能使用writeTofile(会覆盖)
移动句柄到文件的尾部 [self.writeHandle seekToEndOfFile];
(5)下载完毕的时候,关闭连接
[self.writeHandle closeFile];
3、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,不过很少用
注意:关键代码
从self.currentLength字节部分重新开始读取
NSString *value=[NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
[request setValue:value forHTTPHeaderField:@"Range"];
一、简单说明
来源:https://www.cnblogs.com/asd5551680/p/4180431.html
