我正在尝试将.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 ++中的比较:
原始中存在一些字母,并且在收到时不存在!
这里是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天!
谢谢大家:)
答案 0 :(得分:0)
您可以尝试在发送之前将jpeg编码为base64。据我所知,这是一个合适的解决方案。在服务器上解码它应该没问题。 (Sry,我想写一个评论 - 但我不允许这样做)
答案 1 :(得分:0)
有两个问题:
我将解析器修改为此解析器,它将处理其余部分:
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--
希望它可以帮助别人。