2011-06-26 310 views
2

我正在嘗試讀取圖像並使用Base64編碼將其轉換爲字節數組,然後通過字符串通過網絡發送。問題是,當我嘗試解碼Base64編碼的字符串時,我得到不正確的數據。Base64編碼/解碼問題:解碼後的字符串是'?'

例如,我面臨着以下特殊問題。

我使用下面的代碼編碼:

byte[] b = Base64.encodeBase64(IOUtils.toByteArray(loInputStream)); 
String ab = new String(b); 

IOUtilsorg.apache.commons.io.IOUtils

和loInput

碼解碼:

byte[] c = Base64.decodeBase64(ab.getBytes()); 
String ca = new String(c); 
System.out.println(ca); 

它打印?用於解碼的字符串。

任何人都可以讓我知道這個問題。

+0

class'Base64'來自哪裏(這不是標準的Java API類)? – Jesper

+0

@jesper:我正在使用apache commons(org.apache.commons.codec.binary.Base64) – Ankit

+0

下面的nos已經回答了你的問題。只是一個小小的評論:當將字符串轉換爲字節[]和反之亦然時,最好明確指定編碼,而不要依賴平臺設置。我的意思是它應該是「新字符串(b,」UTF-8「)」和「ab.getBytes(」UTF-8「)」 – Tarlog

回答

1

正如我已經說過elsewhere,在Java中,String是文本,byte[]是二進制數據。

字符串≠字節[]

文本≠二進制數據

的圖像是二進制數據。 Base64是一種允許通過兼容US_ASCII的文本通道傳輸二進制數據的編碼(對於ASCII文本的超集有一個類似的編碼:Quoted Printable)。

因此,它是這樣:

Image (binary data) → Image (text, Base64 encoded binary data) → Image (binary data)

,你會用String encodeBase64String(byte[])編碼,並byte[] decode(String)解碼。這些是Base64的唯一理智的API,byte[] encodeBase64(byte[])是誤導性的,結果是US_ASCII兼容的文本(所以,一個String,而不是byte[])。

現在,文本具有一個字符集和編碼,String內部使用一個固定的Unicode/UTF-16字符集/編碼組合,你必須從/轉換的東西時,爲String,顯式指定字符集/編碼,或者隱式地使用平臺的默認編碼(這是PrintStream.println()所做的)。 Base64文本是純粹的US_ASCII,所以你需要使用它,或US_ASCII的超集。 org.apache.commons.codec.binary.Base64使用UTF8,這是US_ASCII的超集,所以一切都很好。 (OTOH,內部java.util.prefs.Base64使用平臺的默認編碼,所以我猜如果你用UTF-16編碼啓動你的JVM,它會中斷)。

返回主題:您已嘗試將解碼圖像(二進制數據)作爲文本打印出來,這顯然不起作用。 PrintStreamwrite()方法可以寫入二進制數據,所以你可以使用這些,你會得到相同的垃圾,就像你寫了原始圖像。使用FileOutputStream會更好,並將生成的文件與原始圖像文件進行比較。

4

如果您的輸入是圖像,則將其編碼爲base64是合理的 - base64是文本,並且可以用字符串表示。

雖然解碼它,但您會看到原始圖像。圖像通常是二進制格式;嘗試將其轉換爲字符串沒有任何意義 - 它不是文本。

也就是說,最後兩行:

String ca = new String(c); 
    System.out.println(ca); 

根本沒有意義的事情。

如果你想檢查解碼是否產生與原始輸入相同的輸出,

System.out.println("Original and decoded are the same: " + Arrays.equals(b,c)); 

(或字節數組保存到一個文件,並查看圖像查看器中的圖像)

+0

@nos:感謝您的回覆,我之所以將它轉換回字符串是因爲我想再次使用Base64編碼重新創建該圖像串。有沒有其他的方式來做同樣的事情? – Ankit

+0

@nos:我將這個編碼的字符串發送到我的應用程序,該應用程序使用我的CMS api(alfresco)創建圖像,該圖像將String作爲圖像數據的輸入參數。 – Ankit

+2

@Ankit你已經在'byte [] c = Base64.decodeBase64(ab.getBytes())''這一行重新創建了它,''數組'c'現在是原始圖像。如果你的露天api將圖像作爲一個字符串,你需要閱讀關於它期望的格式的文檔。也許API期望你發送圖像的base64編碼表示。 (即你發送它的結果'byte b [] = Base64.encodeBase64(IOUtils.toByteArray(loInputStream)); String ab = new String(b);' – nos