iOS文件傳輸的底層實現

一.前言

之前對AFNetWorking二次封裝上傳圖片的方法是以文件流的方式上傳的,上傳文件有兩張方式:1.已文件流的方式上傳 2.將image轉成NSData,在進行base64加密上傳(NSString imageString = [data base64EncodedStringWithOptions:0];轉成base64字符串imageString,再傳給給后臺,在傳參中需要添加圖片的類型(@“png”或@“jpg”等))。兩種方式選擇哪一種,取決于后臺以哪種方式接受文件。對于第二種方式很簡單,第一種方式AFNetWoring也封裝好了,下面我們從最底層文件傳輸探討,也就是AFNetWoring內部是怎么實現文件流傳輸的。即探討一下
-(void)appendPartWithFileData:(NSData *)data
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType;
到底是怎么實現的

二.單個文件傳輸(AFN在個別情況下不能完成,可直接用最底層方法傳輸)
 / /分割符:必須不能包含中文
      #define CZBoundary @"baidu"
  /**
  *  上傳文件
  *
  *  @param fileData   fileData 上傳文件的二進制數據
  *  @param fieldName fieldName 上傳到服務器的字段名
  *  @param fileNamefileName上傳文件名
  */
 - (void)uploadFile:(NSData *)fileData fieldName:(NSString 
  *)fieldName fileName:(NSString *)fileName
  {
//url   upload.php 是驗證上傳的腳本  它內部規定了保存在服務器哪個路徑  和傳入服務器的字段名 這是后臺給的路徑
NSURL *url = [NSURL URLWithString:@"http://192.168.51.9/post/upload.php"];
//request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//設置請求方法
request.HTTPMethod = @"POST";
/* Content-Type
 multipart/form-data; boundary=itcast*/
//設置contentType
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",CZBoundary] forHTTPHeaderField:@"Content-Type"];
//設置請求體
request.HTTPBody = [self fileData:fileData fieldName:fieldName fileName:fileName];
//發送請求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSLog(@"%@---%@",response,dict);
}];
 }
 /**
   *  設置請求體二進制
  *
   *  @param fileData   fileData 上傳文件的二進制數據
  *  @param fieldName fieldName description
  *  @param fileNamefileName上傳文件名
 *
*  @return 請求體
*/
  - (NSData *)fileData:(NSData *)fileData fieldName:(NSString 
  *)fieldName fileName:(NSString *)fileName
   {
//創建一個可變二進制數據
NSMutableData *dataM = [NSMutableData data];
//創建一個可變字符串
NSMutableString *strM = [NSMutableString string];
[strM appendFormat:@"--%@\r\n",CZBoundary];
[strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
[strM appendFormat:@"Content-Type: application/octet-stream\r\n\r\n"];

//將strM的內容拼接到dataM中
[dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];

//拼接文件的二進制數據
[dataM appendData:fileData];

//拼接結尾標識
NSString *tail = [NSString stringWithFormat:@"\r\n--%@--",CZBoundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];


//拼接文件的二進制數據
return dataM;
}
  • 調用示范

       -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:
         (UIEvent *)event
         {
          NSString *filePath = [[NSBundle 
         mainBundle]pathForResource:@"1.png" ofType:nil];
       NSData *fileData = [NSData dataWithContentsOfFile:filePath];
       [self uploadFile:fileData fieldName:@"userfile" 
       fileName:@"1.png"];
      }
    
三.多個文件傳輸
   /**
   *  上傳多個文件
    *
   *  @param fileDict  多個文件字典
   *  @param fieldName 上傳到服務器的字段
   *  @param params    普通參數字典
    */
   - (void)uploadFile:(NSDictionary *)fileDict fieldName:
  (NSString *)fieldName params:(NSDictionary *)params
  {
//url   upload.php 是驗證上傳的腳本  它內部規定了保存在服務器哪個路徑 這是后臺給的路徑
NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload-m.php"];
//request
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//設置請求方法
request.HTTPMethod = @"POST";
/* Content-Type
 multipart/form-data; boundary=itcast*/
//設置contentType
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",CZBoundary] forHTTPHeaderField:@"Content-Type"];
//設置請求體
request.HTTPBody = [self fileData:fileDict fieldName:fieldName params:params];
//發送請求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSLog(@"%@---%@",response,dict);
}];
}
  /**
   *  設置請求體二進制
    *
     @param fileDict  多個文件字典
   *  @param fieldName 上傳到服務器的字段
   *  @param params    普通參數字典
   *
   *  @return 請求體
    */
  - (NSData *)fileData:(NSDictionary *)fileDict fieldName:
 (NSString *)fieldName params:(NSDictionary *)params
{
//創建一個可變二進制數據
NSMutableData *dataM = [NSMutableData data];

//遍歷文件字典
[fileDict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull fileName, id  fileData, BOOL * _Nonnull stop) {
        //創建一個可變字符串
         NSMutableString *strM = [NSMutableString string];
        [strM appendFormat:@"--%@\r\n",CZBoundary];
        [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",fieldName,fileName];
        [strM appendFormat:@"Content-Type: application/octet-stream\r\n\r\n"];
        //將strM的內容拼接到dataM中
        [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
    
        //拼接文件的二進制數據
        [dataM appendData:fileData];
        //拼接當前文件結尾標志
        NSString *tail = [NSString stringWithFormat:@"\r\n--%@\r\n",CZBoundary];
        [dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
    
}];

//遍歷普通參數 key是接受普通參數的字段 obj是普通參數內容
[params enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
    //創建一個可變字符串
    NSMutableString *strM = [NSMutableString string];
    [strM appendFormat:@"Content-Disposition: form-data; name=%@\r\n\r\n",key];
    [strM appendFormat:@"%@",obj];
    [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];

}];

//拼接結尾標識
NSString *tail = [NSString stringWithFormat:@"\r\n--%@--",CZBoundary];
[dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];
 //
  //    //拼接文件的二進制數據

return dataM;
 }
  • 多個文件上傳調用示范

        / /分割符:必須不能包含中文
       #define CZBoundary @"baidu"
     -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:
      (UIEvent *)event
      {
       NSString *filePath1 = [[NSBundle 
      mainBundle]pathForResource:@"1.png" ofType:nil];
      NSData *fileData1 = [NSData 
      dataWithContentsOfFile:filePath1];
       NSString *filePath2 = [[NSBundle 
       mainBundle]pathForResource:@"11.png" ofType:nil];
       NSData *fileData2 = [NSData dataWithContentsOfFile:filePath2];
       /        /普通參數
        NSString *username = @"file";
        //接受文件數據的字段名:userfile[] 接受普通參數的字段
    名:username
        //文件字典
       NSDictionary *fileDict = 
       @{@"1.png":fileData1,@"11.png":fileData2};
        //普通參數字典 @"username"后臺給的傳入普通參數的字段名  
       value自己傳入的參數
       NSDictionary *params = @{@"username":username};
       //確定要傳入的文件  找后臺要路徑和傳入服務器的字段名 確定參數 
        [self uploadFile:fileDict fieldName:@"userfile[]" params:params];
     }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • /**ios常見的幾種加密方法: 普通的加密方法是講密碼進行加密后保存到用戶偏好設置( [NSUserDefaul...
    彬至睢陽閱讀 3,017評論 0 7
  • iOS開發系列--網絡開發 概覽 大部分應用程序都或多或少會牽扯到網絡開發,例如說新浪微博、微信等,這些應用本身可...
    lichengjin閱讀 3,721評論 2 7
  • 218.241.181.202 wxhl60 123456 192.168.10.253 wxhl66 wxhl6...
    CYC666閱讀 1,443評論 0 6
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,217評論 30 472
  • 1,采用蘋果原生NSMutableURLRequest請求 //1. NSURLNSURL *url = [NSU...
    千里從閱讀 397評論 0 0