2012-07-03 86 views
7

下面的代碼Java錯誤?爲什麼utf8編碼中額外的零字節?

public class CharsetProblem { 
public static void main(String[] args) { 
    //String str = "aaaaaaaaa"; 
    String str = "aaaaaaaaaa"; 
    Charset cs1 = Charset.forName("ASCII"); 
    Charset cs2 = Charset.forName("utf8"); 

    System.out.println(toHex(cs1.encode(str).array())); 
    System.out.println(toHex(cs2.encode(str).array())); 

} 

public static String toHex(byte[] outputBytes) { 

    StringBuilder builder = new StringBuilder(); 

    for(int i=0; i<outputBytes.length; ++i) { 
     builder.append(String.format("%02x", outputBytes[i])); 
    } 

    return builder.toString(); 
} 
} 

返回

61616161616161616161 
6161616161616161616100 

即UTF8編碼返回過量字節。如果我們減少一個-s,那麼我們就不會有多餘的字節。如果我們採取更多的a-s,我們可以得到越來越多的多餘字節。

爲什麼?

如何解決這個問題?

回答

6

你不能只獲得支持數組並使用它。 ByteBuffers有一個capacity, position and a limit

System.out.println(cs1.encode(str).remaining()); 
System.out.println(cs2.encode(str).remaining()); 

生產:

10 
10 

試試這個:

public static void main(String[] args) { 
    //String str = "aaaaaaaaa"; 
    String str = "aaaaaaaaaa"; 
    Charset cs1 = Charset.forName("ASCII"); 
    Charset cs2 = Charset.forName("utf8"); 

    System.out.println(toHex(cs1.encode(str))); 
    System.out.println(toHex(cs2.encode(str))); 
} 

public static String toHex(ByteBuffer buff) { 
    StringBuilder builder = new StringBuilder(); 
    while (buff.remaining() > 0) { 
    builder.append(String.format("%02x", buff.get())); 
    } 
    return builder.toString(); 
} 

它產生預期:

61616161616161616161 
61616161616161616161 
6

假設ByteBuffer的支持陣列恰好是保存內容的正確大小,但並不一定。實際上,內容甚至不需要從數組的第一個字節開始!研究ByteBuffer的API,你就會明白髮生了什麼:內容從arrayOffset()返回的值開始,返回的結束。

2

答案已經給出,但我跑進入同樣的問題,我想可能可用於提供更多詳細信息:

通過調用cs1.encode(str).array()cs2.encode(str).array()返回的字節數組返回當時分配給ByteBuffer的整個數組的引用。數組的容量可能比實際使用的容量大。要僅檢索使用的部分,您應該執行以下操作:

ByteBuffer bf1 = cs1.encode(str); 
ByteBuffer bf2 = cs2.encode(str); 
System.out.println(toHex(Arrays.copyOf(bf1.array(), bf1.limit()))); 
System.out.println(toHex(Arrays.copyOf(bf2.array(), bf2.limit()))); 

這會產生您期望的結果。

相關問題