iOS原生文件上傳

首先聲明,利用蘋果自帶的進(jìn)行API進(jìn)行上傳的話,很蛋疼的. 所以一般公司都會(huì)使用原生API進(jìn)行上傳和下載, 用的都是三方框架AFNetwork,ASIHTTPRequest等

現(xiàn)在開始說明利用NSURLConnection進(jìn)行上傳文件,需要對(duì)請(qǐng)求體進(jìn)行設(shè)置. 只有請(qǐng)求體知道上傳數(shù)據(jù)的格式以及相關(guān)的配置.[蛋疼的是,格式很難寫, 一個(gè)標(biāo)點(diǎn),一個(gè)換行都不能有錯(cuò)誤......] [當(dāng)然可以將邊界進(jìn)行宏定義, 但是對(duì)于邊界必須統(tǒng)一, 而且前面的橫線數(shù)不能少]
/**
     *  post的上傳文件,不同于普通的數(shù)據(jù)上傳,
     *  普通上傳,只是將數(shù)據(jù)轉(zhuǎn)換成二進(jìn)制放置在請(qǐng)求體中,進(jìn)行上傳,有響應(yīng)體得到結(jié)果。
     *  post上傳,當(dāng)上傳文件是, 請(qǐng)求體中會(huì)多一部分東西, Content——Type,這是在請(qǐng)求體中必須要書寫的,而且必須要書寫正確,不能有一個(gè)標(biāo)點(diǎn)符號(hào)的錯(cuò)誤。負(fù)責(zé)就會(huì)請(qǐng)求不上去,或者出現(xiàn)請(qǐng)求的錯(cuò)誤(無名的問題等)
     *  其中在post 請(qǐng)求體中加入的格式有{1、邊界 2、參數(shù) 3、換行 4、具體數(shù)據(jù) 5、換行 6、邊界 7、換行 8、對(duì)象 9、結(jié)束符}
     */
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    // 設(shè)置請(qǐng)求頭數(shù)據(jù) 。  boundary:邊界
    [request setValue:@"multipart/form-data; boundary=----WebKitFormBoundaryftnnT7s3iF7wV5q6" forHTTPHeaderField:@"Content-Type"];
    
    // 給請(qǐng)求體加入固定格式數(shù)據(jù)
    NSMutableData *data = [NSMutableData data];
/*******************設(shè)置文件參數(shù)***********************/
    // 設(shè)置邊界 注:必須和請(qǐng)求頭數(shù)據(jù)設(shè)置的邊界 一樣, 前面多兩個(gè)“-”;(字符串 轉(zhuǎn) data 數(shù)據(jù))
    [data appendData:[@"------WebKitFormBoundaryftnnT7s3iF7wV5q6" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // 設(shè)置傳入數(shù)據(jù)的基本屬性, 包括有 傳入方式 data ,傳入的類型(名稱) ,傳入的文件名, 。
    [data appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"image.jpeg\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 設(shè)置 內(nèi)容的類型  “文件類型/擴(kuò)展名” MIME中的
    [data appendData:[@"Content-Type: image/jpeg" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // 加入數(shù)據(jù)內(nèi)容
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
   UIImage *image = [UIImage imageNamed:@"pause"];
    NSData *imageData = UIImagePNGRepresentation(image);
    [data appendData:imageData];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];   
 [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // 設(shè)置邊界
    [data appendData:[@"------WebKitFormBoundaryftnnT7s3iF7wV5q6" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
/******************非文件參數(shù)***************************/
    // 內(nèi)容設(shè)置 , 設(shè)置傳入的類型(名稱)
    [data appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 傳入的名稱username = lxl
    [data appendData:[@"lxl" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // 退出邊界
    [data appendData:[@"------WebKitFormBoundaryftnnT7s3iF7wV5q6--" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    request.HTTPBody = data;
    
    // 設(shè)置請(qǐng)求方式 post
    request.HTTPMethod = @"POST";
    
    
    
    [NSURLConnection sendAsynchronousRequest:request  queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
     }];
Snip20151003_2.png

1.對(duì)請(qǐng)求頭添加一個(gè)參數(shù);
2.主要是拼接下面的請(qǐng)求體;[數(shù)據(jù)Data]

怎么得到一個(gè)文件的MIME---文件類型/擴(kuò)展名

給NSString添加分類, 主要用于得出文件的MIME[只有在響應(yīng)頭中才有真實(shí)屬性]

+ (NSString *)mimeWithString:(NSString *)string
{
// 先從參入的路徑的出URL
    NSURL *url = [NSURL fileURLWithPath:string];  
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    // 只有響應(yīng)頭中才有其真實(shí)屬性 也就是MIME
    NSURLResponse *response = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    
    return response.MIMEType;
}
// 在控制器中的調(diào)用
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    NSString *path = @"/Users/liujiaxin/Desktop/image.jpeg";
    NSString *mime = [NSString mimeWithString:path];
    NSLog(@"%@",mime);  
}

對(duì)于上傳文件較大時(shí),我們需要監(jiān)聽它的上傳進(jìn)度,,小文件直接調(diào)用block來返回上傳結(jié)果, 如果需要監(jiān)聽上傳進(jìn)度,則需要進(jìn)行代理處理
代理 -- NSURLConnectionDataDelegate-- 中提供了監(jiān)聽的方法

// totalBytesWritten:目前上傳寫入的文件的大小
// totalBytesExpectedToWrite :預(yù)期需要寫入文件的總大小
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite{
    float progress = (float)1.0 * totalBytesWritten / totalBytesExpectedToWrite;
    NSLog(@"%f",progress);
}
接下來我們來說明利用NSURLSession怎么來做到文件的上傳.其實(shí)和NSURLConnection大同小異, 都需要拼接蛋疼的東西
 
    NSURLSession *session = [NSURLSession sharedSession];
    
    

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 設(shè)置請(qǐng)求頭數(shù)據(jù) 。  boundary:邊界
    [request setValue:@"multipart/form-data; boundary=----WebKitFormBoundaryftnnT7s3iF7wV5q6" forHTTPHeaderField:@"Content-Type"];
    
    // 給請(qǐng)求頭加入固定格式數(shù)據(jù)
    NSMutableData *data = [NSMutableData data];
/****************文件參數(shù)相關(guān)設(shè)置*********************/
    // 設(shè)置邊界 注:必須和請(qǐng)求頭數(shù)據(jù)設(shè)置的邊界 一樣, 前面多兩個(gè)“-”;(字符串 轉(zhuǎn) data 數(shù)據(jù))
    [data appendData:[@"------WebKitFormBoundaryftnnT7s3iF7wV5q6" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // 設(shè)置傳入數(shù)據(jù)的基本屬性, 包括有 傳入方式 data ,傳入的類型(名稱) ,傳入的文件名, 。
    [data appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"image.jpeg\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 設(shè)置 內(nèi)容的類型  “文件類型/擴(kuò)展名” MIME中的
    [data appendData:[@"Content-Type: image/jpeg" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
// 加入數(shù)據(jù)內(nèi)容   
 NSData *contentData = [NSData dataWithContentsOfFile:@"/Users/liujiaxin/Desktop/image.jpeg"];
    [data appendData:contentData];
   [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // 設(shè)置邊界
    [data appendData:[@"------WebKitFormBoundaryftnnT7s3iF7wV5q6" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
/******************非文件參數(shù)相關(guān)設(shè)置**********************/
    //  設(shè)置傳入的類型(名稱)
    [data appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 傳入的名稱username = lxl
    [data appendData:[@"lxl" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    // 退出邊界
    [data appendData:[@"------WebKitFormBoundaryftnnT7s3iF7wV5q6--" dataUsingEncoding:NSUTF8StringEncoding]];
    [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

 
    request.HTTPBody = data;        
    request.HTTPMethod = @"POST";    
    NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:data completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    [task resume];
    NSLog(@"+++++++++++++");
}

對(duì)于上傳任務(wù)的監(jiān)聽, 大文件的上傳會(huì)不停的調(diào)用代理方法
---NSURLSessionTaskDelegate--代理方法:

#pragma mark - NSURLSessionTaskDelegate

/**
 *  監(jiān)聽上傳進(jìn)度
 *
 *  @param session
 *  @param task                     上傳任務(wù)
 *  @param bytesSent                當(dāng)前這次發(fā)送的數(shù)據(jù)
 *  @param totalBytesSent           已經(jīng)發(fā)送的總數(shù)據(jù)
 *  @param totalBytesExpectedToSend 期望發(fā)送的總數(shù)據(jù)
 */
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
    float progress = (float)1.0*totalBytesSent / totalBytesExpectedToSend;
    NSLog(@"%f",progress);
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    NSLog(@"%s",__func__);
}
對(duì)于上傳和下載,以及直接從服務(wù)器讀取數(shù)據(jù),等等,如果直接想得到結(jié)果,就調(diào)用block , 如果想監(jiān)聽過程就調(diào)用代理. 一般來說,小文件處理都是block,大文件處理都是代理解決的. 因?yàn)?交互思想,不允許有對(duì)用戶不友好的界面的產(chǎn)生
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,868評(píng)論 18 139
  • iOS開發(fā)系列--網(wǎng)絡(luò)開發(fā) 概覽 大部分應(yīng)用程序都或多或少會(huì)牽扯到網(wǎng)絡(luò)開發(fā),例如說新浪微博、微信等,這些應(yīng)用本身可...
    lichengjin閱讀 3,707評(píng)論 2 7
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,204評(píng)論 30 471
  • iOS網(wǎng)絡(luò)架構(gòu)討論梳理整理中。。。 其實(shí)如果沒有APIManager這一層是沒法使用delegate的,畢竟多個(gè)單...
    yhtang閱讀 5,251評(píng)論 1 23
  • 今天準(zhǔn)備,期待已久,三天健康快樂營的運(yùn)動(dòng)物品,快干衣,水杯,計(jì)步器…主辦方晚上 還在開籌備會(huì)議,辛苦了!
    步步嬌閱讀 201評(píng)論 0 0