我的应用程序中有一个图像上传方法,需要将图像和字符串发送到我的服务器。
问题是服务器接收内容(图像和字符串),但是当它将图像保存在磁盘上时,它已损坏并且无法打开。
这是剧本的相关部分。
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 :(得分:3)
执行new String(byteArray)
时,它会将二进制文件转换为默认字符集(通常为UTF-8)。大多数字符集不适合二进制数据。换句话说,如果您要将某些二进制字符串编码为UTF-8然后解码回二进制,则不会得到相同的二进制字符串。
由于您使用的是多部分编码,因此需要直接写入实体流。 Apache HTTP Client有助手执行此操作。 See this guide或this Android guide上传多部分。
如果您只需要使用字符串,则可以使用
安全地将字节数组转换为字符串String byteStr = android.util.Base64.encode(byteArray, android.util.Base64.DEFAULT);
但重要的是要注意,您的服务器需要Base64将字符串解码回字节数组并将其保存到图像中。此外,传输大小将更大,因为Base64编码不像原始二进制文件那样节省空间。
答案 1 :(得分: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);
}
我一般不推荐这个解决方案,但它可以帮助你完成你的工作。