一、文件下载

获取资源文件大小有两张方式

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