2012-07-03 10 views
7

Następujący kodBłąd Java? Po co dodatkowy bajt zerowy w kodowaniu 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(); 
} 
} 

powraca

61616161616161616161 
6161616161616161616100 

tj utf8 kodowania powraca nadmiar bajtu. Jeśli zajmiemy mniej a-s, to nie będziemy mieli nadmiarowych bajtów. Jeśli przyjmiemy więcej a-s, możemy uzyskać więcej i więcej bajtów nadmiarowych.

Dlaczego?

Jak można to obejść?

Odpowiedz

6

Nie można po prostu uzyskać tablicy zabezpieczającej i używać jej. ByteBuffers mają capacity, position and a limit.

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

produkuje:

10 
10 

Spróbuj to zamiast:

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(); 
} 

Produkuje oczekiwana:

61616161616161616161 
61616161616161616161 
6

Zakładasz, że tablica podkładowa dla ByteBuffer jest dokładnie właściwym rozmiarem do przechowywania zawartości, ale niekoniecznie. W rzeczywistości zawartość nie musi zaczynać się od pierwszego bajtu tablicy! Zapoznaj się z API dla ByteBuffer, aby zrozumieć, co się dzieje: zawartość zaczyna się od wartości zwróconej przez arrayOffset(), a koniec jest zwracany przez limit().

2

Odpowiedź została udzielona, ​​ale jak wpadłem w ten sam problem, myślę, że może być użytecznym, aby podać więcej szczegółów:

Tablica bajtów zwrócona przez wywołanie cs1.encode(str).array() lub cs2.encode(str).array() zwraca odwołanie do całej tablicy przydzielonej do ByteBuffer w tym czasie. Pojemność tablicy może być większa niż ta, która została faktycznie użyta. Aby pobrać tylko zużytą część, wykonaj następujące czynności:

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()))); 

Daje to oczekiwany wynik.

Powiązane problemy