2015-06-07 63 views
0

我有一些編碼爲UTF-8字符串的二進制數據。我怎樣才能從字符串中獲取原始數據?二進制數據沒有特定的字符編碼,所以我不確定什麼轉換會給我想要的。請看下面的小例子:如何獲取用於構造字符串的字節[]?

byte[] input = { -84 }; 
String s = new String(input, Charset.forName("UTF8")); 
System.out.println(Arrays.toString(s.getBytes())); // prints [63] 
System.out.println(Arrays.toString(s.getBytes("UTF8"))); // prints [-17, -65, -67] 

而且我在尋找,讓我回[-84]的方法。

+0

在UTF8中字節值'-84'解碼爲什麼? –

+0

對不起,我不明白你的問題。如果我打印'''我得到'?'。如果我評估'Character.getNumericValue(s.charAt(0))'我得到'-1'。 –

+0

如何用UTF-8解碼值-84? UTF-8是一種定義良好的字符編碼。 -84轉化爲什麼值? –

回答

4

一般來說,你不能。並非所有的字節序列都是有效的UTF-8。因此,數據可能在(容錯)byte[]->char[]->byte[]進程中損壞。

你可以使用,雖然編碼ISO_8859_1,它是一個一對一映射byte<->char

這不是一個罕見的問題。很多老年協議,如HTTP,都是以ISO_8859_1字符爲開頭,或者C的char類型。新版本的規格說它是基於「八位字節」,又名「字節」。如果您的API使用字符串來表示它們,ISO_8859_1通常是更好的選擇。

1

字節-840xAC)本身不是有效的UTF-8字節序列。 (UTF-8僅使用多字節字符序列中的0到127範圍以外的字節來編碼外來字符)。因此,UTF-8解碼器用字符U+FFFD(Unicode「替換字符」)替換輸入字節。 (這可能會在控制檯中顯示爲普通問號。)無法從該字符串中恢復原始字節數組,因爲其他無效字節序列也會解碼爲替換字符。

你可以執行以下操作:

  • 解釋二進制數據作爲具有字節和字符之間的1對1映射的字符編碼。 ISO-8859-1是最方便的選擇,因爲它是保證在任何Java實現中可用的六種基本編碼之一,並且具有預定義的StandardCharsets常量。如果存在,任何舊的DOS代碼頁(例如,Charset.forName("CP437"))也將工作。

  • 推出自己的byte[]char[]轉換。確切的映射是任意的,可以是任何你喜歡的,只要它是無損的。由於該類型的寬度爲16位,因此可能通過在每個Java中包裝兩個字節來減少內存中每個字符串的大小,但這可能不值得大驚小怪。

  • Encode the binary data as text,諸如通過Base64。這種編碼本身會使數據變長,但如果字符串獲得額外的編碼,則可以縮短它。

    例如,如果您嘗試將二進制數據作爲參數in a URL傳遞,則對Base64進行編碼是有意義的。取一個長度爲256的字節數組,其中包含每個可能的字節值中的一個(它將用作任何均勻隨機數據,壓縮數據或加密數據的模型)。如果在Base64中使用填充剝離進行編碼並使用修改後的URL安全的Base64字母表,它將佔用342個字符,但在URL編碼並作爲URL查詢參數傳遞時不會再增長或完全更改。然而,被「解碼」的字節數組就像是一個ISO-8859-1字符串一樣,只需要256個字符,但當它被放到一個URL中時,它會變成肥胖的634個字符,因爲URL編碼是針對純文本,而不是二進制數據。

  • 避免將二進制數據作爲在第一位置的字符串。如果可能的話,直接使用字節數組。如果您的目的是獲取字符串數據的字符串特性(例如不變性和indexOf搜索),則更好地爲數組創建封裝類。
+0

@AndyShulman編號爲'-84'和'-19'的二進制文件是'10101100'和'11101101'。將這些與UTF-8字節序列的描述進行比較[這裏](https://en.wikipedia.org/wiki/UTF-8#Description)。你看到匹配'10xxxxxx'的字節只能作爲多字節序列的第二個和後續字節有效,匹配'1110xxxx'的字節只有在它們後面有兩個「10xxxxxx」字節時纔有效。所以數據仍然是無效的UTF-8,因此這兩個字節爲什麼最終成爲一對'63'(它們是問​​號字符)。 – Boann

相關問題