你好,歡迎來到IOS教程網

 Ios教程網 >> IOS使用技巧 >> IOS技巧綜合 >> IOS And WCF 上傳文件

IOS And WCF 上傳文件

編輯:IOS技巧綜合
[摘要]本文是對IOS And WCF 上傳文件的講解,對學習IOS蘋果軟件開發有所幫助,與大家分享。

IOS And WCF Story

研究IOS上傳到WCF圖片的小功能,WCF實現服務端的文件上傳的例子很多,單獨實現IOS發送圖片的例子也很多,但是兩個結合起來的就很少了。
可以通過base64來上傳圖片,這個方式比較簡單,但是我想要的是通過網絡流來傳送,這樣以後IOS發送任何的文件,服務器不需要修改就能直接來用。想法很簡單,但是歷程很辛苦。。。

IOS發送

首先研究一下IOS端的圖片傳輸,我用的網絡框架是AFNetWorking,附上代碼

NSString *filename=@"test.jpg";
AFHTTPRequestOperationManager *AFManager=[[AFHTTPRequestOperationManager alloc]initWithBaseURL:[NSURL URLWithString:@FileTranUrl]];
AFHTTPRequestOperation *operation=[AFManager POST:path parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formdata){[formdata appendPartWithFileData:imagedata name:name fileName:filename mimeType:@"image/jpeg"];} success:^(AFHTTPRequestOperation *operation, id responseObject) {
    if (success) {
        success(operation,responseObject);
    }
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    if (failure) {
        failure(operation,error);
    }
}];

imagedata是image轉換為NSdata後的值。

這裡的代碼看起來很多,其實很簡單,關鍵只有一處就是

[formdata appendPartWithFileData:imagedata name:name fileName:filename mimeType:@"image/jpeg"];

AFMultipartFormData 做了什麼呢?

查看它的appendPartWithFileData:name:filename:mimeType:源代碼,我們可以看到

- (void)appendPartWithFileData:(NSData *)data
                      name:(NSString *)name
                  fileName:(NSString *)fileName
                  mimeType:(NSString *)mimeType
{
  NSParameterAssert(name);
  NSParameterAssert(fileName);
  NSParameterAssert(mimeType);

  NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
  [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
  [mutableHeaders setValue:mimeType forKey:@"Content-Type"];

  [self appendPartWithHeaders:mutableHeaders body:data];
}

multableHeaders包含了name,filename,mimeType再次查看最後一個方法的定義

 - (void)appendPartWithHeaders:(NSDictionary *)headers
                     body:(NSData *)body
{
    NSParameterAssert(body);

    AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
    bodyPart.stringEncoding = self.stringEncoding;
    bodyPart.headers = headers;
    bodyPart.boundary = self.boundary;
    bodyPart.bodyContentLength = [body length];
    bodyPart.body = body;

    [self.bodyStream appendHTTPBodyPart:bodyPart];
}

[self.bodyStream appendHTTPBodyPart:bodyPart];看到這裡的時候我們已經明白了,以上所有包含的數據全部放到網絡流裡了。為什麼要查看這些呢?因為WCF需要契約定義,我們不知道AFNetwork發送的時候我們應該用什麼契約來接受這個方法。

WCF接受

通過上面的分析,我們已經大概知道契約的定義了

void(Stream requestStream)

WCF在接受數據之前還需要進行配置,在

<system.serviceModel>
<bindings>
  <webHttpBinding>
    <binding name="WebConfiguration"
             maxBufferSize="65536"
             maxReceivedMessageSize="2000000000"
             transferMode="Streamed">
    </binding>
  </webHttpBinding>
  </bindings>

<services>      
  <!--文件服務-->
  <service name="WcfServiceForIOS.ServiceForIOSFile" behaviorConfiguration="ServiceBehavior">
    <endpoint address=""  binding="webHttpBinding" behaviorConfiguration="web"   bindingConfiguration="WebConfiguration"  contract="WcfServiceForIOS.IServiceForIOSFile" />
  </service>
  
</services>
<behaviors>
  <endpointBehaviors>
    <behavior name="web">
      <webHttp />
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>      
  </serviceBehaviors>
</behaviors>
</system.serviceModel>

嘗試實現契約的主要代碼

using (targetStream = new FileStream(filePathAndName, FileMode.Create, FileAccess.Write, FileShare.None))
{
   const int bufferLen = 4096;
   Byte[] buffer = new Byte[bufferLen];
  int count = 0;

   while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)
    {
     targetStream.Write(buffer, 0, count);
     filesize += count;
    }
    targetStream.Close();
    sourceStream.Close();                  
           
             
}

等IOS上傳圖片後,可以在相應的文件夾中找到生成的圖片,但是不幸的是我們無法打開,提示圖片損壞太大。用NotePad++打開這個文件流,可以看到以下代碼

--Boundary+4AA85CFEE4A1D140
Content-Disposition: form-data; name="file"; filename="test.jpg"
Content-Type: image/jpeg
(亂碼,目測是圖片的數據流)
--Boundary+4AA85CFEE4A1D140--

是不是和發送時候的很眼熟,這樣和前面的分析就對上了,傳輸過來的文件流是包含圖片的信息和圖片的數據。需要分開處理。
處理方法和web發送的form-data是一樣的,先編碼為string,通過正則表達取出各個屬性值

 private void Parse(Stream stream, Encoding encoding)
    {
        this.Success = false;

        // Read the stream into a byte array
        byte[] data = ToByteArray(stream);
        requestData = data;

        // Copy to a string for header parsing
        string content = encoding.GetString(data);

        // The first line should contain the delimiter
        int delimiterEndIndex = content.IndexOf("\r\n");

        if (delimiterEndIndex > -1)
        {
            string delimiter = content.Substring(0, content.IndexOf("\r\n"));

            // Look for Content-Type
            Regex re = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");
            Match contentTypeMatch = re.Match(content);

            // Look for filename
            re = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")");
            Match filenameMatch = re.Match(content);

            // Did we find the required values?
            if (contentTypeMatch.Success && filenameMatch.Success)
            {
                // Set properties
                this.ContentType = contentTypeMatch.Value.Trim();
                this.Filename = filenameMatch.Value.Trim();

                // Get the start & end indexes of the file contents
                int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;

                byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
                int endIndex = IndexOf(data, delimiterBytes, startIndex);

                int contentLength = endIndex - startIndex;

                // Extract the file contents from the byte array
                byte[] fileData = new byte[contentLength];

                Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);

                this.FileContents = fileData;
                this.Success = true;
            }
        }
    } 

取出各個段後就能用來存文件了

參考連接

    stackOverFlow_1
    stackOverFlow_2
    逆時針の風Cnblog
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved