将多部分文件从android上传到WCF

时间:2015-08-28 07:46:57

标签: java c# android wcf file-upload

我正在尝试将.JPG文件从android上传到WCF webservice。

要从Android上传文件我试过两种方法:

1 - Retrofit:

        @Multipart
        @POST("/UploadFile/{fileName}")
        void UploadFile(@Path("fileName") String fileName, @Part("image") TypedFile image, Callback<String> callBack);

2 - Android Asynchronous Http Client

这里有2个上传选项:

a - 将InputStream添加到RequestParams:

        RequestParams params = new RequestParams();
        try {
            InputStream stream = new FileInputStream(fileImage);
            params.put("image", stream, fileImage.getName() );
            client.post(Constants.SERVICE_URL + "/UploadFile/" + fileImage.getName()
                            , params, getResponseHandler());
        } catch (Exception e) {
            Utils.LogError("ERROR: " + e.getLocalizedMessage());
        }

b - Ading File对象到RequestParams:

        RequestParams params = new RequestParams();
        try {
            //InputStream stream = new FileInputStream(fileImage);
            params.put("image", fileImage);
            client.post(Constants.SERVICE_URL + "/UploadFile/" + fileImage.getName()
                            , params, getResponseHandler());
        } catch (Exception e) {
            Utils.LogError("ERROR: " + e.getLocalizedMessage());
        }

所有这些,成功发送到服务器,解析之前收到的文件看起来像这样:

--b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b
Content-Disposition: form-data; name="image"; filename="71d9d7fc-cfa8-40b6-b7aa-5c287cf31c72.jpg"
Content-Type: image/jpeg
Content-Length: 2906
Content-Transfer-Encoding: binary

���� JFIF      �� C .................very long string of this stuff
Þq�Ã�9�A?� �0pi1�zq�<�#��:��PV���]|�e�K�mv �ǜ.1�q���&��8��u�m�?�ӵ/���0=8�x�:t�8��>�ׁ���1�POM�k����eea1��ǧq�}8�6��q� � �� .;p1K�g�Onz�Q�oås�a�׌p1�?>3@���z��0=��m$�H ǧ��Ӄ�v?��x��<q��.8܃��� ��2}1�� c���ϧ q�oA�Rt>��t�=�?����2y�q�큊A����:��q�@���_�~�Q�w��Pu��Ƿ�q�#q��{cۦ���}0:b�|�=@��9�BEV���?O��װ�g���׎z<N� ��� v�=�?������=�<}x�#'�d�8��׌e����,�\�4wVV���f�pB���㢁�L{��%$�v裶G8x��b�?���� �]�=:�ӕ����
--b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b--

所以我使用mulipart解析器来取出文件的字节,将它们写入服务器上的文件以完成上传。

以下是我使用的multipartparser的代码:

  public class MultipartParser
   {
public MultipartParser(string contents)
{
  this.Parse(contents);
}

private void Parse(string contents)
{
  Encoding encoding = Encoding.UTF8;
  this.Success = false;

  // Read the stream into a byte array
  byte[] data = encoding.GetBytes(contents);

  // Copy to a string for header parsing
  string content = contents;

  // 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)");
    Match contentTypeMatch = re.Match(content);

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

    #region added
    re = new Regex(@"(?<=Content\-Transfer\-Encoding:)(.*?)(?=\r\n\r\n)");
    Match contentTransferEncodingMatch = re.Match(content);
    #endregion

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


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

      byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
      string finalDelimeterStr = "\r\n"+delimiter + "--";
      byte[] endDilimeterBytes = encoding.GetBytes(finalDelimeterStr);
      //byte[] fileBytes = Array.Copy()
      //int endIndex = IndexOf(data, endDilimeterBytes, startIndex);
      int endIndex = SimpleBoyerMooreSearch(data, endDilimeterBytes);

      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;
    }
  }
}

public int SimpleBoyerMooreSearch(byte[] haystack, byte[] needle)
{
  int[] lookup = new int[256];
  for (int i = 0; i < lookup.Length; i++) { lookup[i] = needle.Length; }

  for (int i = 0; i < needle.Length; i++)
  {
    lookup[needle[i]] = needle.Length - i - 1;
  }

  int index = needle.Length - 1;
  byte lastByte = needle.Last();
  while (index < haystack.Length)
  {
    var checkByte = haystack[index];
    if (haystack[index] == lastByte)
    {
      bool found = true;
      for (int j = needle.Length - 2; j >= 0; j--)
      {
        if (haystack[index - needle.Length + j + 1] != needle[j])
        {
          found = false;
          break;
        }
      }

      if (found)
        return index - needle.Length + 1;
      else
        index++;
    }
    else
    {
      index += lookup[checkByte];
    }
  }
  return -1;
}

public static byte[] ToByteArray(Stream stream)
{
  byte[] buffer = new byte[32768];
  using (MemoryStream ms = new MemoryStream())
  {
    while (true)
    {
      int read = stream.Read(buffer, 0, buffer.Length);
      if (read <= 0)
        return ms.ToArray();
      ms.Write(buffer, 0, read);
    }
  }
}

public bool Success
{
  get;
  private set;
}

public string ContentType
{
  get;
  private set;
}
public string ContentEncoding
{
  get;
  private set;
}


public string Filename
{
  get;
  private set;
}

public byte[] FileContents
{
  get;
  private set;
}

}

解析器取出字节,并解析收到的多部分文件。

结果文件未显示,显示错误读取文件或其他内容。

在比较文件之后我注意到原始文件和接收文件不同,这是Notepad ++中的比较:

Orig Rec comp

原始中存在一些字母,并且在收到时不存在!

这里是WCF函数声明和代码:

IService.cs:

[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "/UploadFile/{fileName}"
  , ResponseFormat = WebMessageFormat.Json)]
string UploadFile(string fileName ,Stream image);

Service.cs:

public string UploadFile(string fileName, Stream image)
{
  string dirPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Logs/");
  //string path = dirPath+"log.txt";

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

  // Copy to a string
  string content = Encoding.UTF8.GetString(data);

  File.WriteAllText(dirPath + fileName + ".txt", content); // for checking the result file

  MultipartParser parser = new MultipartParser(content);

  if (parser != null )
  {
    if (parser.Success)
    {

      if (parser.FileContents == null)
        return "fail: Null Content";

      byte[] bitmap = parser.FileContents;

      File.WriteAllBytes(dirPath + fileName +"contents",bitmap);

      try
      {
        using (Image outImage = Image.FromStream(new MemoryStream(bitmap)))
        {
          outImage.Save(fileName, ImageFormat.Jpeg);
        }
        return "success";
      }
      catch (Exception e)
      { // I get this exception all the time
        return "Fail: e " + e.Message;
      }
    }
    return "fail not success";
  }

  return "fail";
}

我尝试了所有可能的解决方案来到我的脑海中,仍然无法得到什么错误!是发送或解析器时编码的问题!??

请问可能是什么问题!?我正在为此奋斗3天!

谢谢大家:)

2 个答案:

答案 0 :(得分:0)

您可以尝试在发送之前将jpeg编码为base64。据我所知,这是一个合适的解决方案。在服务器上解码它应该没问题。 (Sry,我想写一个评论 - 但我不允许这样做)

答案 1 :(得分:0)

有两个问题:

  1. 解析器
  2. 将字节解码为字符串并不是一个好主意。
  3. 我将解析器修改为此解析器,它将处理其余部分:

    public class MultipartParser
    
    
    {
        public MultipartParser(Stream stream)
    {
      this.Parse(stream);
    }
    
    private void Parse(Stream stream)
    {
      this.Success = false;
      if(!stream.CanRead)
        return;
    
      // Read the stream into a byte array
      byte[] data = MultipartParser.ToByteArray(stream);
      if (data.Length < 1)
        return;
    
      // finding the delimiter (the string in the beginning and end of the file
      int delimeterIndex = MultipartParser.SimpleBoyerMooreSearch(data, Encoding.UTF8.GetBytes("\r\n")); // here we got delimeter index
      if (delimeterIndex == -1) return;
      byte[] delimeterBytes = new byte[delimeterIndex];
      Array.Copy(data, delimeterBytes, delimeterIndex);
    
      // removing the very first couple of lines, till we get the beginning of the JPG file
      byte[] newLineBytes = Encoding.UTF8.GetBytes("\r\n\r\n");
      int startIndex = 0;
    
      startIndex = MultipartParser.SimpleBoyerMooreSearch(data, newLineBytes);
      if (startIndex == -1)
        return;
    
      int startIndexWith2Lines = startIndex + 4; // 4 is the bytes of "\r\n\r\n"
      int newLength = data.Length - startIndexWith2Lines;
      byte[] newByteArray = new byte[newLength];
    
      Array.Copy(data, startIndex + 4, newByteArray, 0, newLength - 1);
    
      // check for the end of the stream, is ther same delimeter
      int isThereDelimeterInTheEnd = MultipartParser.SimpleBoyerMooreSearch(newByteArray, delimeterBytes);
      if (isThereDelimeterInTheEnd == -1) return; // the file corrupted so
    
      int endIndex = isThereDelimeterInTheEnd - delimeterBytes.Length;
    
      byte[] lastArray = new byte[endIndex];
    
      Array.Copy(newByteArray, 0, lastArray, 0, endIndex);
    
      this.FileContents = lastArray;
      this.Success = true;
    }
    static byte[] GetBytes(string str)
    {
      byte[] bytes = new byte[str.Length * sizeof(char)];
      System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
      return bytes;
    }
    
    static string GetString(byte[] bytes)
    {
      char[] chars = new char[bytes.Length / sizeof(char)];
      System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
      return new string(chars);
    }
    
    
    public static int SimpleBoyerMooreSearch(byte[] haystack, byte[] needle)
    {
      int[] lookup = new int[256];
      for (int i = 0; i < lookup.Length; i++) { lookup[i] = needle.Length; }
    
      for (int i = 0; i < needle.Length; i++)
      {
        lookup[needle[i]] = needle.Length - i - 1;
      }
    
      int index = needle.Length - 1;
      byte lastByte = needle.Last();
      while (index < haystack.Length)
      {
        var checkByte = haystack[index];
        if (haystack[index] == lastByte)
        {
          bool found = true;
          for (int j = needle.Length - 2; j >= 0; j--)
          {
            if (haystack[index - needle.Length + j + 1] != needle[j])
            {
              found = false;
              break;
            }
          }
    
          if (found)
            return index - needle.Length + 1;
          else
            index++;
        }
        else
        {
          index += lookup[checkByte];
        }
      }
      return -1;
    }
    
    private int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex)
    {
      int index = 0;
      int startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex);
    
      if (startPos != -1)
      {
        while ((startPos + index) < searchWithin.Length)
        {
          if (searchWithin[startPos + index] == serachFor[index])
          {
            index++;
            if (index == serachFor.Length)
            {
              return startPos;
            }
          }
          else
          {
            startPos = Array.IndexOf<byte>(searchWithin, serachFor[0], startPos + index);
            if (startPos == -1)
            {
              return -1;
            }
            index = 0;
          }
        }
      }
    
      return -1;
    }
    
    public static byte[] ToByteArray(Stream stream)
    {
      byte[] buffer = new byte[32768];
      using (MemoryStream ms = new MemoryStream())
      {
        while (true)
        {
          int read = stream.Read(buffer, 0, buffer.Length);
          if (read <= 0)
            return ms.ToArray();
          ms.Write(buffer, 0, read);
        }
      }
    }
    
    public bool Success
    {
      get;
      private set;
    }
    
    public byte[] FileContents
    {
      get;
      private set;
    }
    
    
    }
    

    因此,您可以将此解析器用于此类多部分文件编码:

    --b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b
    Content-Disposition: form-data; name="image"; filename="71d9d7fc-cfa8-40b6-b7aa-5c287cf31c72.jpg"
    Content-Type: image/jpeg
    Content-Length: 2906
    Content-Transfer-Encoding: binary
    
    ���� JFIF      �� C .................very long string of this stuff
    Þq�Ã�9�A?� �0pi1�zq�<�#��:��PV���]|�e�K�mv �ǜ.1�q���&��8��u�m�?�ӵ/��Ƿ�q�#q��{cۦ���}0:b�|�=@��9�BEV���?O��װ�g���׎z<N� ��� v�=�?������=�<}x�#'�d�8��׌e����,�\�4wVV���f�pB���㢁�L{��%$�v裶G8x��b�?���� �]�=:�ӕ����
    --b1b13fd2-4212-45bb-bb5c-fd4dc074fd1b--
    

    希望它可以帮助别人。