2016-03-07 180 views
2

我在我的应用程序中有一个图像上传方法,需要将图像和字符串发送到我的服务器。将图像上传到服务器会破坏图像

问题是服务器接收到内容(图像和字符串),但是当它将图像保存在磁盘上时,它已损坏,无法打开。

这是脚本的相关部分。

HttpPost httpPost = new HttpPost(url); 

Bitmap bmp = ((BitmapDrawable) imageView.getDrawable()).getBitmap(); 
ByteArrayOutputStream stream = new ByteArrayOutputStream(); 

bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); 

byte[] byteArray = stream.toByteArray(); 
String byteStr = new String(byteArray); 

StringBuilder stringBuilder = new StringBuilder(); 
stringBuilder.append("--"+boundary+"\r\n"); 
stringBuilder.append("Content-Disposition: form-data; name=\"content\"\r\n\r\n"); 
stringBuilder.append(message+"\r\n"); 

stringBuilder.append("--"+boundary+"\r\n"); 
stringBuilder.append("Content-Disposition: form-data; name=\"image\"; filename=\"image.jpg\"\r\n"); 

stringBuilder.append("Content-Type: image/jpeg\r\n\r\n"); 

stringBuilder.append(byteStr); 
stringBuilder.append("\r\n"); 

stringBuilder.append("--"+boundary+"--\r\n"); 
StringEntity entity = new StringEntity(stringBuilder.toString()); 
httpPost.setEntity(entity); 

我无法更改服务器,因为其他客户端使用它,它适用于他们。我只需要了解为什么图像被损坏。

+0

我只是猜测,但你有没有检查enconding?你从图像数据创建String时不指定字符集:'new String(byteArray,??)' – Peter

+0

你是什么意思?我怎样才能做到这一点? –

回答

3

当您执行new String(byteArray)时,它将二进制转换为默认字符集(通常为UTF-8)。大多数字符集不适合二进制数据的编码。换句话说,如果您要将某些二进制字符串编码为UTF-8,然后解码回二进制,则不会得到相同的二进制字符串。

由于您使用的是多部分编码,因此您需要直接写入实体流。 Apache HTTP Client有这样做的助手。 See this guidethis Android guide上传多部分。

如果你只需要使用字符串,就可以安全的字节数组转换成字符串

String byteStr = android.util.Base64.encode(byteArray, android.util.Base64.DEFAULT); 

但要注意,您的服务器将需要Base64编码解码的字符串返回一个字节数组是非常重要的并将其保存到图像。而且,由于Base64编码不像原始二进制那样具有空间效率,因此传输大小会更大。

+0

这对我们不起作用。我们不想使用该库。如果我们可以更喜欢只使用字符串发送信息。 –

+0

@NicosKaralis你喜欢什么并不重要,你没有选择。您必须直接写入字节,而不是通过“字符串”。 – EJP

+0

@NicosKaralis如果您有控制服务器代码的权限,您可以使用Base64编码(适用于编码二进制数据)编码图像,然后在服务器端解码并保存图像。这可能需要额外的努力。 – Samuel

0

由于您使用的是new String(byteArray),因此您的解决方案无法正常工作。构造函数使用默认编码对字节数组进行编码 - 请参阅What is the default encoding - 很可能您的数据中的字节序列不能编码为字符。

更确切地说,字符集定义字符如何表示为字节。 大多数字符集都有超过256个字符。这就是为什么你需要多个字节来表示一个字符的原因。 UTF-8和UTF-16最多使用四个字节。 所以你有一个数字空间和字符空间之间的映射,这个映射是先验不可见的。所以很可能在数字空间中存在一个没有字符映射到它的数字。

建议的解决方案@Samuel是万无一失的,因为Base64使用A-Z,a-z,0-9,+,/并以=结尾以表示一个字节。我更喜欢这个解决方案!

如果您不想或不能使用Base64,那么您可以试着将每个字节放入StringBuilder,希望服务器在获取之前不会进行任何编码。

for (byte b : byteArray) { 
    stringBuilder.append((char)b); 
} 

我一般不会推荐这个解决方案,但它可以帮助你完成你的工作。