iOS 文件上传 post数据

//联系人:石虎  QQ: 1224614774昵称:嗡嘛呢叭咪哄


一、文件下载

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

1、

[objc] view plain copy
  1. HTTP HEAD方法  
  2. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeout];  
  3. request.HTTPMethod = @"HEAD";  
  4. [NSURLConnection sendAsynchronousRequest:request queue:self.myQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {  
  5.     NSLog(@"%@", response);  
  6.     NSLog(@"---------------");  
  7.     NSLog(@"%@", data);  
  8. }];  
  9. 运行测试代码可以发现,HEAD方法只是返回资源信息,而不会返回数据体  
  10. 应用场景:  
  11. 获取资源Mimetype  
  12. 获取资源文件大小,用于端点续传或多线程下载  
2

[objc] view plain copy
  1. 使用块代码获取网络资源大小的方法  
  2. - (void)fileSizeWithURL:(NSURL *)url completion:(void (^)(long long contentLength))completion  
  3. {  
  4.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeout];  
  5.     request.HTTPMethod = @"HEAD";   
  6.     NSURLResponse *response = nil;  
  7.     [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];  
  8.       
  9.     completion(response.expectedContentLength);  
  10. }  

确定每次下载数据包的伪代码实现

[objc] view plain copy
  1. - (void)downloadFileWithURL:(NSURL *)url  
  2. {  
  3.     [self fileSizeWithURL:url completion:^(long long contentLength) {  
  4.         NSLog(@"文件总大小:%lld", contentLength);          
  5.         // 根据大小下载文件  
  6.                while (contentLength > kDownloadBytes) {  
  7.             NSLog(@"每次下载长度:%lld", (long long)kDownloadBytes);  
  8.             contentLength -= kDownloadBytes;  
  9.         }  
  10.         NSLog(@"最后下载字节数:%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,不过很少用

[objc] view plain copy
  1. 分段Range代码实现  
  2. long long fromBytes = 0;  
  3. long long toBytes = 0;  
  4. while (contentLength > kDownloadBytes) {  
  5.     toBytes = fromBytes + kDownloadBytes - 1;  
  6.     NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", fromBytes, toBytes];  
  7.     NSLog(@"range %@", range);  
  8.     fromBytes += kDownloadBytes;  
  9.     contentLength -= kDownloadBytes;  
  10. }  
  11. fromBytes = fromBytes + contentLength - 1;  
  12. NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", fromBytes, toBytes];  
  13. NSLog(@"range %@", range);  

[objc] view plain copy
  1. 分段下载文件  
  2. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeout];  
  3. NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", from, end];  
  4. [request setValue:range forHTTPHeaderField:@"Range"];  
  5.   
  6. NSURLResponse *response = nil;  
  7. NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];  
  8.       
  9. NSLog(@"%@-%@-%ld", range, response, (unsigned long)data.length);  
  10. 提示:  
  11. 如果GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是200(OK)  

[objc] view plain copy
  1. 将数据写入文件  
  2. // 打开缓存文件  
  3. NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.cachePath];  
  4. // 如果文件不存在,直接写入数据  
  5. if (!fp) {  
  6.     [data writeToFile:self.cachePath atomically:YES];  
  7. else {  
  8.     // 移动到文件末尾  
  9.     [fp seekToEndOfFile];  
  10.     // 将数据文件追加到文件末尾  
  11.     [fp writeData:data];  
  12.     // 关闭文件句柄  
  13.     [fp closeFile];  
  14. }  

[objc] view plain copy
  1. 检查文件大小  
  2. // 判断文件是否存在  
  3. if ([[NSFileManager defaultManager] fileExistsAtPath:self.cachePath]) {  
  4.     NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.cachePath error:NULL];  
  5.     return [dict[NSFileSize] longLongValue];  
  6. else {  
  7.     return 0;  
  8. }  
  9.   
  10. 提示:由于数据是追加的,为了避免重复从网络下载文件,在下载之前  
  11. 判断缓存路径中文件是否已经存在  
  12. 如果存在检查文件大小  
  13. 如果文件大小与网络资源大小一致,则不再下载  

全部代码如下

[objc] view plain copy

  1. //  01.文件下载  

  2. //  
  3.   
  4. #import "MJViewController.h"  
  5. #import "FileDownload.h"  
  6.   
  7. @interface MJViewController ()  
  8. @property (nonatomicstrongFileDownload *download;  
  9. @property (weak, nonatomic) IBOutlet UIImageView *imageView;  
  10. @end  
  11.   
  12. @implementation MJViewController  
  13.   
  14. - (void)viewDidLoad  
  15. {  
  16.     [super viewDidLoad];  
  17.       
  18.     self.download = [[FileDownload alloc] init];  
  19.     [self.download downloadFileWithURL:[NSURL URLWithString:@"http://localhost/itcast/images/head4.png"] completion:^(UIImage *image) {  
  20.           
  21.         self.imageView.image = image;  
  22.     }];  
  23. }  
  24.   
  25. @end  

[objc] view plain copy
  1. //  
  2. //  FileDownload.m  
  3. //  01.文件下载  .  
  4. //  
  5.   
  6. #import "FileDownload.h"  
  7. #import "NSString+Password.h"  
  8.   
  9. #define kTimeOut        2.0f  
  10. // 每次下载的字节数  
  11. #define kBytesPerTimes  20250  
  12.   
  13. @interface FileDownload()  
  14. @property (nonatomicstrongNSString *cacheFile;  
  15. @property (nonatomicstrongUIImage *cacheImage;  
  16. @end  
  17.   
  18. @implementation FileDownload  
  19. /** 
  20.  为了保证开发的简单,所有方法都不使用多线程,所有的注意力都保持在文件下载上 
  21.   
  22.  在开发中如果碰到比较绕的计算问题时,建议: 
  23.  1> 测试数据不要太大 
  24.  2> 测试数据的数值变化,能够用笔算计算出准确的数值 
  25.  3> 编写代码对照测试 
  26.  
  27.  */  
  28. //- (NSString *)cacheFile  
  29. //{  
  30. //    if (!_cacheFile) {  
  31. //        NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];  
  32. //        _cacheFile = [cacheDir stringByAppendingPathComponent:@"123.png"];  
  33. //    }  
  34. //    return _cacheFile;  
  35. //}  
  36. - (UIImage *)cacheImage  
  37. {  
  38.     if (!_cacheImage) {  
  39.         _cacheImage = [UIImage imageWithContentsOfFile:self.cacheFile];  
  40.     }  
  41.     return _cacheImage;  
  42. }  
  43.   
  44. - (void)setCacheFile:(NSString *)urlStr  
  45. {  
  46.     NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];  
  47.     urlStr = [urlStr MD5];  
  48.       
  49.     _cacheFile = [cacheDir stringByAppendingPathComponent:urlStr];  
  50. }  
  51.   
  52. - (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(UIImage *image))completion  
  53. {  
  54.     // GCD中的串行队列异步方法  
  55.     dispatch_queue_t q = dispatch_queue_create("cn.itcast.download", DISPATCH_QUEUE_SERIAL);  
  56.       
  57.     dispatch_async(q, ^{  
  58.         NSLog(@"%@", [NSThread currentThread]);  
  59.           
  60.         // 把对URL进行MD5加密之后的结果当成文件名  
  61.         self.cacheFile = [url absoluteString];  
  62.           
  63.         // 1. 从网络下载文件,需要知道这个文件的大小  
  64.         long long fileSize = [self fileSizeWithURL:url];  
  65.         // 计算本地缓存文件大小  
  66.         long long cacheFileSize = [self localFileSize];  
  67.           
  68.         if (cacheFileSize == fileSize) {  
  69.             dispatch_async(dispatch_get_main_queue(), ^{  
  70.                 completion(self.cacheImage);  
  71.             });  
  72.             NSLog(@"文件已经存在");  
  73.             return;  
  74.         }  
  75.           
  76.         // 2. 确定每个数据包的大小  
  77.         long long fromB = 0;  
  78.         long long toB = 0;  
  79.         // 计算起始和结束的字节数  
  80.         while (fileSize > kBytesPerTimes) {  
  81.             // 20480 + 20480  
  82.             //  
  83.             toB = fromB + kBytesPerTimes - 1;  
  84.               
  85.             // 3. 分段下载文件  
  86.             [self downloadDataWithURL:url fromB:fromB toB:toB];  
  87.               
  88.             fileSize -= kBytesPerTimes;  
  89.             fromB += kBytesPerTimes;  
  90.         }  
  91.         [self downloadDataWithURL:url fromB:fromB toB:fromB + fileSize - 1];  
  92.   
  93.         dispatch_async(dispatch_get_main_queue(), ^{  
  94.             completion(self.cacheImage);  
  95.         });          
  96.     });  
  97. }  
  98.   
  99. #pragma mark 下载指定字节范围的数据包  
  100. /** 
  101.  NSURLRequestUseProtocolCachePolicy = 0,        // 默认的缓存策略,内存缓存 
  102.   
  103.  NSURLRequestReloadIgnoringLocalCacheData = 1,  // 忽略本地的内存缓存 
  104.  NSURLRequestReloadIgnoringCacheData 
  105.  */  
  106. - (void)downloadDataWithURL:(NSURL *)url fromB:(long long)fromB toB:(long long)toB  
  107. {  
  108.     NSLog(@"数据包:%@", [NSThread currentThread]);  
  109.       
  110.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeOut];  
  111.       
  112.     // 指定请求中所要GET的字节范围  
  113.     NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld", fromB, toB];  
  114.     [request setValue:range forHTTPHeaderField:@"Range"];  
  115.     NSLog(@"%@", range);  
  116.       
  117.     NSURLResponse *response = nil;  
  118.     NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];  
  119.       
  120.     // 写入文件,覆盖文件不会追加  
  121. //    [data writeToFile:@"/Users/aplle/Desktop/1.png" atomically:YES];  
  122.     [self appendData:data];  
  123.       
  124.     NSLog(@"%@", response);  
  125. }  
  126.   
  127. #pragma mark - 读取本地缓存文件大小  
  128. - (long long)localFileSize  
  129. {  
  130.     // 读取本地文件信息  
  131.     NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.cacheFile error:NULL];  
  132.     NSLog(@"%lld", [dict[NSFileSize] longLongValue]);  
  133.       
  134.     return [dict[NSFileSize] longLongValue];  
  135. }  
  136.   
  137. #pragma mark - 追加数据到文件  
  138. - (void)appendData:(NSData *)data  
  139. {  
  140.     // 判断文件是否存在  
  141.     NSFileHandle *fp = [NSFileHandle fileHandleForWritingAtPath:self.cacheFile];  
  142.     // 如果文件不存在创建文件  
  143.     if (!fp) {  
  144.         [data writeToFile:self.cacheFile atomically:YES];  
  145.     } else {  
  146.         // 如果文件已经存在追加文件  
  147.         // 1> 移动到文件末尾  
  148.         [fp seekToEndOfFile];  
  149.         // 2> 追加数据  
  150.         [fp writeData:data];  
  151.         // 3> 写入文件  
  152.         [fp closeFile];  
  153.     }  
  154. }  
  155.   
  156. #pragma mark - 获取网络文件大小  
  157. - (long long)fileSizeWithURL:(NSURL *)url  
  158. {  
  159.     // 默认是GET  
  160.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeOut];  
  161.       
  162.     // HEAD 头,只是返回文件资源的信息,不返回具体是数据  
  163.     // 如果要获取资源的MIMEType,也必须用HEAD,否则,数据会被重复下载两次  
  164.     request.HTTPMethod = @"HEAD";  
  165.   
  166.     // 使用同步方法获取文件大小  
  167.     NSURLResponse *response = nil;  
  168.       
  169.     [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];  
  170.       
  171.     // expectedContentLength文件在网络上的大小  
  172.     NSLog(@"%lld", response.expectedContentLength);  
  173.       
  174.     return response.expectedContentLength;  
  175. }  
  176.   
  177. @end  


二、文件上传

代码如下

[objc] view plain copy
  1. //  
  2. //  MJViewController.m  
  3. //  02.Post上传  
  4.   
  5. //  
  6.   
  7. #import "MJViewController.h"  
  8. #import "UploadFile.h"  
  9.   
  10. @interface MJViewController ()  
  11.   
  12. @end  
  13.   
  14. @implementation MJViewController  
  15.   
  16. - (void)viewDidLoad  
  17. {  
  18.     [super viewDidLoad];  
  19.   
  20.     UploadFile *upload = [[UploadFile alloc] init];  
  21.       
  22.     NSString *urlString = @"http://localhost/upload.php";  
  23.       
  24.     NSString *path = [[NSBundle mainBundle] pathForResource:@"头像1.png" ofType:nil];  
  25.     NSData *data = [NSData dataWithContentsOfFile:path];  
  26.       
  27.     [upload uploadFileWithURL:[NSURL URLWithString:urlString] data:data];  
  28. }  
  29.   
  30. @end  

[objc] view plain copy
  1. //  
  2. //  UploadFile.m  
  3. //  02.Post上传  
  4. //  
  5.   
  6. #import "UploadFile.h"  
  7.   
  8. @implementation UploadFile  
  9. // 拼接字符串  
  10. static NSString *boundaryStr = @"--";   // 分隔字符串  
  11. static NSString *randomIDStr;           // 本次上传标示字符串  
  12. static NSString *uploadID;              // 上传(php)脚本中,接收文件字段  
  13.   
  14. - (instancetype)init  
  15. {  
  16.     self = [super init];  
  17.     if (self) {  
  18.         randomIDStr = @"itcast";  
  19.         uploadID = @"uploadFile";  
  20.     }  
  21.     return self;  
  22. }  
  23.   
  24. #pragma mark - 私有方法  
  25. - (NSString *)topStringWithMimeType:(NSString *)mimeType uploadFile:(NSString *)uploadFile  
  26. {  
  27.     NSMutableString *strM = [NSMutableString string];  
  28.       
  29.     [strM appendFormat:@"%@%@\n", boundaryStr, randomIDStr];  
  30.     [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\n", uploadID, uploadFile];  
  31.     [strM appendFormat:@"Content-Type: %@\n\n", mimeType];  
  32.       
  33.     NSLog(@"%@", strM);  
  34.     return [strM copy];  
  35. }  
  36.   
  37. - (NSString *)bottomString  
  38. {  
  39.     NSMutableString *strM = [NSMutableString string];  
  40.       
  41.     [strM appendFormat:@"%@%@\n", boundaryStr, randomIDStr];  
  42.     [strM appendString:@"Content-Disposition: form-data; name=\"submit\"\n\n"];  
  43.     [strM appendString:@"Submit\n"];  
  44.     [strM appendFormat:@"%@%@--\n", boundaryStr, randomIDStr];  
  45.       
  46.     NSLog(@"%@", strM);  
  47.     return [strM copy];  
  48. }  
  49.   
  50. #pragma mark - 上传文件  
  51. - (void)uploadFileWithURL:(NSURL *)url data:(NSData *)data  
  52. {  
  53.     // 1> 数据体  
  54.     NSString *topStr = [self topStringWithMimeType:@"image/png" uploadFile:@"头像1.png"];  
  55.     NSString *bottomStr = [self bottomString];  
  56.       
  57.     NSMutableData *dataM = [NSMutableData data];  
  58.     [dataM appendData:[topStr dataUsingEncoding:NSUTF8StringEncoding]];  
  59.     [dataM appendData:data];  
  60.     [dataM appendData:[bottomStr dataUsingEncoding:NSUTF8StringEncoding]];  
  61.       
  62.     // 1. Request  
  63.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:2.0f];  
  64.       
  65.     // dataM出了作用域就会被释放,因此不用copy  
  66.     request.HTTPBody = dataM;  
  67.       
  68.     // 2> 设置Request的头属性  
  69.     request.HTTPMethod = @"POST";  
  70.       
  71.     // 3> 设置Content-Length  
  72.     NSString *strLength = [NSString stringWithFormat:@"%ld", (long)dataM.length];  
  73.     [request setValue:strLength forHTTPHeaderField:@"Content-Length"];  
  74.       
  75.     // 4> 设置Content-Type  
  76.     NSString *strContentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", randomIDStr];  
  77.     [request setValue:strContentType forHTTPHeaderField:@"Content-Type"];  
  78.       
  79.     // 3> 连接服务器发送请求  
  80.     [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {  
  81.           
  82.         NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
  83.         NSLog(@"%@", result);  
  84.     }];  
  85. }  
  86.   
  87.   
  88.   
  89. @end  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值