ios 多線程文件下載與上傳, post數據

1、文件下載
php

獲取資源文件大小有兩張方式數組

一、xcode

 

[objc]  view plaincopy在CODE上查看代碼片派生到個人代碼片
  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 plaincopy在CODE上查看代碼片派生到個人代碼片
  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 plaincopy在CODE上查看代碼片派生到個人代碼片
  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 plaincopy在CODE上查看代碼片派生到個人代碼片
  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 plaincopy在CODE上查看代碼片派生到個人代碼片
  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 plaincopy在CODE上查看代碼片派生到個人代碼片
  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 plaincopy在CODE上查看代碼片派生到個人代碼片
  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 plaincopy在CODE上查看代碼片派生到個人代碼片
  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 alloc] init];  
  24.     [self.download downloadFileWithURL:[NSURL URLWithString:@"http://localhost/itcast/images/head4.png"] completion:^(UIImage *image) {  
  25.           
  26.         self.imageView.image = image;  
  27.     }];  
  28. }  
  29.   
  30. @end  

 

[objc]  view plaincopy在CODE上查看代碼片派生到個人代碼片
  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.         _cacheImage = [UIImage imageWithContentsOfFile:self.cacheFile];  
  43.     }  
  44.     return _cacheImage;  
  45. }  
  46.   
  47. - (void)setCacheFile:(NSString *)urlStr  
  48. {  
  49.     NSString *cacheDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];  
  50.     urlStr = [urlStr MD5];  
  51.       
  52.     _cacheFile = [cacheDir stringByAppendingPathComponent:urlStr];  
  53. }  
  54.   
  55. - (void)downloadFileWithURL:(NSURL *)url completion:(void (^)(UIImage *image))completion  
  56. {  
  57.     // GCD中的串行隊列異步方法  
  58.     dispatch_queue_t q = dispatch_queue_create("cn.itcast.download", DISPATCH_QUEUE_SERIAL);  
  59.       
  60.     dispatch_async(q, ^{  
  61.         NSLog(@"%@", [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.                 completion(self.cacheImage);  
  74.             });  
  75.             NSLog(@"文件已經存在");  
  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.             toB = fromB + kBytesPerTimes - 1;  
  87.               
  88.             // 3. 分段下載文件  
  89.             [self downloadDataWithURL:url fromB:fromB toB:toB];  
  90.               
  91.             fileSize -= kBytesPerTimes;  
  92.             fromB += kBytesPerTimes;  
  93.         }  
  94.         [self downloadDataWithURL:url fromB:fromB toB:fromB + fileSize - 1];  
  95.   
  96.         dispatch_async(dispatch_get_main_queue(), ^{  
  97.             completion(self.cacheImage);  
  98.         });          
  99.     });  
  100. }  
  101.   
  102. #pragma mark 下載指定字節範圍的數據包  
  103. /** 
  104.  NSURLRequestUseProtocolCachePolicy = 0,        // 默認的緩存策略,內存緩存 
  105.   
  106.  NSURLRequestReloadIgnoringLocalCacheData = 1,  // 忽略本地的內存緩存 
  107.  NSURLRequestReloadIgnoringCacheData 
  108.  */  
  109. - (void)downloadDataWithURL:(NSURL *)url fromB:(long long)fromB toB:(long long)toB  
  110. {  
  111.     NSLog(@"數據包:%@", [NSThread currentThread]);  
  112.       
  113.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kTimeOut];  
  114.       
  115.     // 指定請求中所要GET的字節範圍  
  116.     NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld", fromB, toB];  
  117.     [request setValue:range forHTTPHeaderField:@"Range"];  
  118.     NSLog(@"%@", range);  
  119.       
  120.     NSURLResponse *response = nil;  
  121.     NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];  
  122.       
  123.     // 寫入文件,覆蓋文件不會追加  
  124. //    [data writeToFile:@"/Users/aplle/Desktop/1.png" atomically:YES];  
  125.     [self appendData:data];  
  126.       
  127.     NSLog(@"%@", response);  
  128. }  
  129.   
  130. #pragma mark - 讀取本地緩存文件大小  
  131. - (long long)localFileSize  
  132. {  
  133.     // 讀取本地文件信息  
  134.     NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:self.cacheFile error:NULL];  
  135.     NSLog(@"%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 = [NSFileHandle fileHandleForWritingAtPath:self.cacheFile];  
  145.     // 若是文件不存在建立文件  
  146.     if (!fp) {  
  147.         [data writeToFile:self.cacheFile atomically:YES];  
  148.     } else {  
  149.         // 若是文件已經存在追加文件  
  150.         // 1> 移動到文件末尾  
  151.         [fp seekToEndOfFile];  
  152.         // 2> 追加數據  
  153.         [fp writeData:data];  
  154.         // 3> 寫入文件  
  155.         [fp closeFile];  
  156.     }  
  157. }  
  158.   
  159. #pragma mark - 獲取網絡文件大小  
  160. - (long long)fileSizeWithURL:(NSURL *)url  
  161. {  
  162.     // 默認是GET  
  163.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:kTimeOut];  
  164.       
  165.     // HEAD 頭,只是返回文件資源的信息,不返回具體是數據  
  166.     // 若是要獲取資源的MIMEType,也必須用HEAD,不然,數據會被重複下載兩次  
  167.     request.HTTPMethod = @"HEAD";  
  168.   
  169.     // 使用同步方法獲取文件大小  
  170.     NSURLResponse *response = nil;  
  171.       
  172.     [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];  
  173.       
  174.     // expectedContentLength文件在網絡上的大小  
  175.     NSLog(@"%lld", response.expectedContentLength);  
  176.       
  177.     return response.expectedContentLength;  
  178. }  
  179.   
  180. @end  

 

 

2、文件上傳app

代碼以下dom

 

[objc]  view plaincopy在CODE上查看代碼片派生到個人代碼片
  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 alloc] init];  
  23.       
  24.     NSString *urlString = @"http://localhost/upload.php";  
  25.       
  26.     NSString *path = [[NSBundle mainBundle] pathForResource:@"頭像1.png" ofType:nil];  
  27.     NSData *data = [NSData dataWithContentsOfFile:path];  
  28.       
  29.     [upload uploadFileWithURL:[NSURL URLWithString:urlString] data:data];  
  30. }  
  31.   
  32. @end  

 

[objc]  view plaincopy在CODE上查看代碼片派生到個人代碼片
  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.         randomIDStr = @"itcast";  
  22.         uploadID = @"uploadFile";  
  23.     }  
  24.     return self;  
  25. }  
  26.   
  27. #pragma mark - 私有方法  
  28. - (NSString *)topStringWithMimeType:(NSString *)mimeType uploadFile:(NSString *)uploadFile  
  29. {  
  30.     NSMutableString *strM = [NSMutableString string];  
  31.       
  32.     [strM appendFormat:@"%@%@\n", boundaryStr, randomIDStr];  
  33.     [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\n", uploadID, uploadFile];  
  34.     [strM appendFormat:@"Content-Type: %@\n\n", mimeType];  
  35.       
  36.     NSLog(@"%@", strM);  
  37.     return [strM copy];  
  38. }  
  39.   
  40. - (NSString *)bottomString  
  41. {  
  42.     NSMutableString *strM = [NSMutableString string];  
  43.       
  44.     [strM appendFormat:@"%@%@\n", boundaryStr, randomIDStr];  
  45.     [strM appendString:@"Content-Disposition: form-data; name=\"submit\"\n\n"];  
  46.     [strM appendString:@"Submit\n"];  
  47.     [strM appendFormat:@"%@%@--\n", boundaryStr, randomIDStr];  
  48.       
  49.     NSLog(@"%@", strM);  
  50.     return [strM copy];  
  51. }  
  52.   
  53. #pragma mark - 上傳文件  
  54. - (void)uploadFileWithURL:(NSURL *)url data:(NSData *)data  
  55. {  
  56.     // 1> 數據體  
  57.     NSString *topStr = [self topStringWithMimeType:@"image/png" uploadFile:@"頭像1.png"];  
  58.     NSString *bottomStr = [self bottomString];  
  59.       
  60.     NSMutableData *dataM = [NSMutableData data];  
  61.     [dataM appendData:[topStr dataUsingEncoding:NSUTF8StringEncoding]];  
  62.     [dataM appendData:data];  
  63.     [dataM appendData:[bottomStr dataUsingEncoding:NSUTF8StringEncoding]];  
  64.       
  65.     // 1. Request  
  66.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:2.0f];  
  67.       
  68.     // dataM出了做用域就會被釋放,所以不用copy  
  69.     request.HTTPBody = dataM;  
  70.       
  71.     // 2> 設置Request的頭屬性  
  72.     request.HTTPMethod = @"POST";  
  73.       
  74.     // 3> 設置Content-Length  
  75.     NSString *strLength = [NSString stringWithFormat:@"%ld", (long)dataM.length];  
  76.     [request setValue:strLength forHTTPHeaderField:@"Content-Length"];  
  77.       
  78.     // 4> 設置Content-Type  
  79.     NSString *strContentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", randomIDStr];  
  80.     [request setValue:strContentType forHTTPHeaderField:@"Content-Type"];  
  81.       
  82.     // 3> 鏈接服務器發送請求  
  83.     [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {  
  84.           
  85.         NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
  86.         NSLog(@"%@", result);  
  87.     }];  
  88. }  
  89.   
  90.   
  91.   
  92. @end  
相關文章
相關標籤/搜索