一、文件下载
获取资源文件大小有两张方式
1、
1. HTTP HEAD方法
2. NSMutableURLRequest *request = [NSMutableURLRequest0 timeoutInterval:kTimeout];
3. request.HTTPMethod = @"HEAD";
4. [NSURLConnectionself.myQueueNSURLResponse *response, NSData *data, NSError *connectionError) {
5. @"%@", response);
6. @"---------------");
7. @"%@", data);
8. }];
9. 运行测试代码可以发现,HEAD方法只是返回资源信息,而不会返回数据体
10. 应用场景:
11. 获取资源Mimetype
12. 获取资源文件大小,用于端点续传或多线程下载
2
1. 使用块代码获取网络资源大小的方法
2. - (void)fileSizeWithURL:(NSURL *)urlvoid (^)(long long contentLength))completion
3. {
4. NSMutableURLRequest *request = [NSMutableURLRequest0 timeoutInterval:kTimeout];
5. .HTTPMethod = @"HEAD";
6. NSURLResponse *response = nil;
7. NULL];
8.
9. .expectedContentLength);
10. }
确定每次下载数据包的伪代码实现
1. - (void)downloadFileWithURL:(NSURL *)url
2. {
3. selflong long contentLength) {
4. @"文件总大小:%lld", contentLength);
5. // 根据大小下载文件
6. while (contentLength > kDownloadBytes) {
7. @"每次下载长度:%lld", (long long)kDownloadBytes);
8. contentLength -= kDownloadBytes;
9. }
10. @"最后下载字节数:%lld", contentLength);
11. }];
12. }
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,不过很少用
1. 分段Range代码实现
2. long long fromBytes = 0;
3. long long toBytes = 0;
4. while (contentLength > kDownloadBytes) {
5. 1;
6. NSString *range = [NSString@"bytes=%lld-%lld", fromBytes, toBytes];
7. @"range %@", range);
8. fromBytes += kDownloadBytes;
9. contentLength -= kDownloadBytes;
10. }
11. fromBytes = fromBytes + contentLength - 1;
12. NSString *range = [NSString@"bytes=%lld-%lld", fromBytes, toBytes];
13. NSLog(@"range %@", range);
1. 分段下载文件
2. NSMutableURLRequest *request = [NSMutableURLRequest timeoutInterval:kTimeout];
3. NSString *range = [NSString@"bytes=%lld-%lld", from, end];
4. [request@"Range"];
5.
6. NSURLResponse *response = nil;
7. NSData *data = [NSURLConnectionNULL];
8.
9. NSLog(@"%@-%@-%ld", range, response, (unsigned long)data.length);
10. 提示:
11. 如果GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是200(OK)
1. 将数据写入文件
2. // 打开缓存文件
3. NSFileHandle *fp = [NSFileHandleself.cachePath];
4. // 如果文件不存在,直接写入数据
5. if (!fp) {
6. self.cachePathYES];
7. } else {
8. // 移动到文件末尾
9. seekToEndOfFile];
10. // 将数据文件追加到文件末尾
11. writeData:data];
12. // 关闭文件句柄
13. closeFile];
14. }
1. 检查文件大小
2. // 判断文件是否存在
3. if ([[NSFileManagerself.cachePath]) {
4. NSDictionary *dict = [[NSFileManagerself.cachePathNULL];
5. return [dict[NSFileSize] longLongValue];
6. } else {
7. return 0;
8. }
9.
10. 提示:由于数据是追加的,为了避免重复从网络下载文件,在下载之前
11. 判断缓存路径中文件是否已经存在
12. 如果存在检查文件大小
13. 如果文件大小与网络资源大小一致,则不再下载
全部代码如下
1. //
2. // MJViewController.m
3. // 01.文件下载
4. //
5. // Created by apple on 14-4-29.
6. // Copyright (c) 2014年 itcast. All rights reserved.
7. //
8.
9. #import "MJViewController.h"
10. #import "FileDownload.h"
11.
12. @interface MJViewController ()
13. @property (nonatomic, strong) FileDownload *download;
14. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
15. @end
16.
17. @implementation MJViewController
18.
19. - (void)viewDidLoad
20. {
21. super viewDidLoad];
22.
23. self.download = [[FileDownload init];
24. self.download@"http://localhost/itcast/images/head4.png"]UIImage *image) {
25.
26. self.imageView.image = image;
27. }];
28. }
29.
30. @end
1. //
2. // FileDownload.m
3. // 01.文件下载
4. //
5. // Created by apple on 14-4-29.
6. // Copyright (c) 2014年 itcast. All rights reserved.
7. //
8.
9. #import "FileDownload.h"
10. #import "NSString+Password.h"
11.
12. #define kTimeOut 2.0f
13. // 每次下载的字节数
14. #define kBytesPerTimes 20250
15.
16. @interface FileDownload()
17. @property (nonatomic, strong) NSString *cacheFile;
18. @property (nonatomic, strong) UIImage *cacheImage;
19. @end
20.
21. @implementation FileDownload
22. /**
23. 为了保证开发的简单,所有方法都不使用多线程,所有的注意力都保持在文件下载上
24.
25. 在开发中如果碰到比较绕的计算问题时,建议:
26. 1> 测试数据不要太大
27. 2> 测试数据的数值变化,能够用笔算计算出准确的数值
28. 3> 编写代码对照测试
29.
30. */
31. //- (NSString *)cacheFile
32. //{
33. // if (!_cacheFile) {
34. // NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
35. // _cacheFile = [cacheDir stringByAppendingPathComponent:@"123.png"];
36. // }
37. // return _cacheFile;
38. //}
39. - (UIImage *)cacheImage
40. {
41. if (!_cacheImage) {
42. self.cacheFile];
43. }
44. return _cacheImage;
45. }
46.
47. - (void)setCacheFile:(NSString *)urlStr
48. {
49. NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
50. MD5];
51.
52. stringByAppendingPathComponent:urlStr];
53. }
54.
55. - (void)downloadFileWithURL:(NSURL *)urlvoid (^)(UIImage *image))completion
56. {
57. // GCD中的串行队列异步方法
58. "cn.itcast.download", DISPATCH_QUEUE_SERIAL);
59.
60. dispatch_async(q, ^{
61. @"%@", [NSThread currentThread]);
62.
63. // 把对URL进行MD5加密之后的结果当成文件名
64. self.cacheFile = [url absoluteString];
65.
66. // 1. 从网络下载文件,需要知道这个文件的大小
67. long long fileSize = [self fileSizeWithURL:url];
68. // 计算本地缓存文件大小
69. long long cacheFileSize = [self localFileSize];
70.
71. if (cacheFileSize == fileSize) {
72. dispatch_async(dispatch_get_main_queue(), ^{
73. self.cacheImage);
74. });
75. @"文件已经存在");
76. return;
77. }
78.
79. // 2. 确定每个数据包的大小
80. long long fromB = 0;
81. long long toB = 0;
82. // 计算起始和结束的字节数
83. while (fileSize > kBytesPerTimes) {
84. // 20480 + 20480
85. //
86. 1;
87.
88. // 3. 分段下载文件
89. self toB:toB];
90.
91. fileSize -= kBytesPerTimes;
92. fromB += kBytesPerTimes;
93. }
94. self 1];
95.
96. dispatch_async(dispatch_get_main_queue(), ^{
97. self.cacheImage);
98. });
99. });
100. }
101.
102. #pragma mark 下载指定字节范围的数据包
103. /**
104. NSURLRequestUseProtocolCachePolicy = 0, // 默认的缓存策略,内存缓存
105.
106. NSURLRequestReloadIgnoringLocalCacheData = 1, // 忽略本地的内存缓存
107. NSURLRequestReloadIgnoringCacheData
108. */
109. - (void)downloadDataWithURL:(NSURL *)urllong long)fromBlong long)toB
110. {
111. @"数据包:%@", [NSThread currentThread]);
112.
113. NSMutableURLRequest *request = [NSMutableURLRequest timeoutInterval:kTimeOut];
114.
115. // 指定请求中所要GET的字节范围
116. NSString *range = [NSString@"Bytes=%lld-%lld", fromB, toB];
117. @"Range"];
118. @"%@", range);
119.
120. NSURLResponse *response = nil;
121. NSData *data = [NSURLConnectionNULL];
122.
123. // 写入文件,覆盖文件不会追加
124. // [data writeToFile:@"/Users/aplle/Desktop/1.png" atomically:YES];
125. self appendData:data];
126.
127. @"%@", response);
128. }
129.
130. #pragma mark - 读取本地缓存文件大小
131. - (long long)localFileSize
132. {
133. // 读取本地文件信息
134. NSDictionary *dict = [[NSFileManagerself.cacheFileNULL];
135. @"%lld", [dict[NSFileSize] longLongValue]);
136.
137. return [dict[NSFileSize] longLongValue];
138. }
139.
140. #pragma mark - 追加数据到文件
141. - (void)appendData:(NSData *)data
142. {
143. // 判断文件是否存在
144. NSFileHandle *fp = [NSFileHandleself.cacheFile];
145. // 如果文件不存在创建文件
146. if (!fp) {
147. self.cacheFileYES];
148. else {
149. // 如果文件已经存在追加文件
150. // 1> 移动到文件末尾
151. seekToEndOfFile];
152. // 2> 追加数据
153. writeData:data];
154. // 3> 写入文件
155. closeFile];
156. }
157. }
158.
159. #pragma mark - 获取网络文件大小
160. - (long long)fileSizeWithURL:(NSURL *)url
161. {
162. // 默认是GET
163. NSMutableURLRequest *request = [NSMutableURLRequest0 timeoutInterval:kTimeOut];
164.
165. // HEAD 头,只是返回文件资源的信息,不返回具体是数据
166. // 如果要获取资源的MIMEType,也必须用HEAD,否则,数据会被重复下载两次
167. .HTTPMethod = @"HEAD";
168.
169. // 使用同步方法获取文件大小
170. NSURLResponse *response = nil;
171.
172. NULL];
173.
174. // expectedContentLength文件在网络上的大小
175. @"%lld", response.expectedContentLength);
176.
177. return response.expectedContentLength;
178. }
179.
180. @end
二、文件上传
代码如下
1. //
2. // MJViewController.m
3. // 02.Post上传
4. //
5. // Created by apple on 14-4-29.
6. // Copyright (c) 2014年 itcast. All rights reserved.
7. //
8.
9. #import "MJViewController.h"
10. #import "UploadFile.h"
11.
12. @interface MJViewController ()
13.
14. @end
15.
16. @implementation MJViewController
17.
18. - (void)viewDidLoad
19. {
20. super viewDidLoad];
21.
22. UploadFile *upload = [[UploadFile init];
23.
24. NSString *urlString = @"http://localhost/upload.php";
25.
26. NSString *path = [[NSBundle@"头像1.png":nil];
27. NSData *data = [NSData dataWithContentsOfFile:path];
28.
29. data:data];
30. }
31.
32. @end
1. //
2. // UploadFile.m
3. // 02.Post上传
4. //
5. // Created by apple on 14-4-29.
6. // Copyright (c) 2014年 itcast. All rights reserved.
7. //
8.
9. #import "UploadFile.h"
10.
11. @implementation UploadFile
12. // 拼接字符串
13. static NSString *boundaryStr = @"--"; // 分隔字符串
14. static NSString *randomIDStr; // 本次上传标示字符串
15. static NSString *uploadID; // 上传(php)脚本中,接收文件字段
16.
17. - (instancetype)init
18. {
19. self = [super init];
20. if (self) {
21. @"itcast";
22. @"uploadFile";
23. }
24. return self;
25. }
26.
27. #pragma mark - 私有方法
28. - (NSString *)topStringWithMimeType:(NSString *)mimeTypeNSString *)uploadFile
29. {
30. NSMutableString *strM = [NSMutableString string];
31.
32. @"%@%@\n", boundaryStr, randomIDStr];
33. @"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\n", uploadID, uploadFile];
34. @"Content-Type: %@\n\n", mimeType];
35.
36. @"%@", strM);
37. return [strM copy];
38. }
39.
40. - (NSString *)bottomString
41. {
42. NSMutableString *strM = [NSMutableString string];
43.
44. @"%@%@\n", boundaryStr, randomIDStr];
45. @"Content-Disposition: form-data; name=\"submit\"\n\n"];
46. @"Submit\n"];
47. @"%@%@--\n", boundaryStr, randomIDStr];
48.
49. @"%@", strM);
50. return [strM copy];
51. }
52.
53. #pragma mark - 上传文件
54. - (void)uploadFileWithURL:(NSURL *)urlNSData *)data
55. {
56. // 1> 数据体
57. NSString *topStr = [self@"image/png"@"头像1.png"];
58. NSString *bottomStr = [self bottomString];
59.
60. NSMutableData *dataM = [NSMutableData data];
61. 8StringEncoding]];
62. appendData:data];
63. 8StringEncoding]];
64.
65. // 1. Request
66. NSMutableURLRequest *request = [NSMutableURLRequest02.0f];
67.
68. // dataM出了作用域就会被释放,因此不用copy
69. .HTTPBody = dataM;
70.
71. // 2> 设置Request的头属性
72. .HTTPMethod = @"POST";
73.
74. // 3> 设置Content-Length
75. NSString *strLength = [NSString@"%ld", (long)dataM.length];
76. @"Content-Length"];
77.
78. // 4> 设置Content-Type
79. NSString *strContentType = [NSString@"multipart/form-data; boundary=%@", randomIDStr];
80. @"Content-Type"];
81.
82. // 3> 连接服务器发送请求
83. NSURLResponse *response, NSData *data, NSError *connectionError) {
84.
85. NSString *result = [[NSString8StringEncoding];
86. @"%@", result);
87. }];
88. }
89.
90.
91.
92. @end