2016-03-07 157 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); 
} 

我一般不會推薦這個解決方案,但它可以幫助你完成你的工作。