2012-07-03 17 views
7

Il codice seguentebug Java? Perché extra zero byte nella codifica 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(); 
} 
} 

rendimenti

61616161616161616161 
6161616161616161616100 

cioè utf8 codifica restituisce eccesso byte. Se prendiamo meno a-s, non avremo byte in eccesso. Se prendiamo più a-s possiamo ottenere sempre più byte in eccesso.

Perché?

Come si può aggirare questo?

risposta

6

Non si può semplicemente ottenere il backing array e usarlo. I ByteBuffer hanno uno capacity, position and a limit.

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

produce:

10 
10 

Prova a modificare:

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

produce l'atteso:

61616161616161616161 
61616161616161616161 
6

Si presume che il backing array per un ByteBuffer sia precisamente la dimensione corretta per contenere i contenuti, ma non è necessariamente. Infatti, il contenuto non ha nemmeno bisogno di iniziare dal primo byte dell'array! Studia l'API per ByteBuffer e capirai cosa sta succedendo: il contenuto inizia dal valore restituito da arrayOffset() e la fine restituita da limit().

2

La risposta è già stata data, ma mentre correvo nello stesso problema, penso che potrebbe essere utile per fornire ulteriori dettagli:

L'array di byte restituito invocando cs1.encode(str).array() o cs2.encode(str).array() restituisce un riferimento all'intero array assegnato a ByteBuffer in quel momento. La capacità dell'array può essere maggiore di quella effettivamente utilizzata. Per recuperare solo la parte utilizzata dovresti fare qualcosa di simile al seguente:

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

Questo produce il risultato che ti aspetti.

Problemi correlati