Domanda

Ho bisogno di codificare / decodificare UTF-16 array di byte da e per java.lang.String. Gli array di byte sono dati da me con una Byte Order Marker (BOM) , e ho bisogno di array di byte codificati con una distinta.

Inoltre, perché ho a che fare con un client Microsoft / server, mi piacerebbe emettere la codifica a little endian (insieme con il LE BOM) al fine di evitare eventuali malintesi. Mi rendo conto che con il BOM dovrebbe funzionare big endian, ma io non voglio nuotare controcorrente nel mondo Windows.

Come esempio, ecco un metodo che codifica una java.lang.String come UTF-16 in little endian con un BOM:

public static byte[] encodeString(String message) {

    byte[] tmp = null;
    try {
        tmp = message.getBytes("UTF-16LE");
    } catch(UnsupportedEncodingException e) {
        // should not possible
        AssertionError ae =
        new AssertionError("Could not encode UTF-16LE");
        ae.initCause(e);
        throw ae;
    }

    // use brute force method to add BOM
    byte[] utf16lemessage = new byte[2 + tmp.length];
    utf16lemessage[0] = (byte)0xFF;
    utf16lemessage[1] = (byte)0xFE;
    System.arraycopy(tmp, 0,
                     utf16lemessage, 2,
                     tmp.length);
    return utf16lemessage;
}

Qual è il modo migliore per fare questo in Java? Idealmente mi piacerebbe evitare di copiare l'intero array di byte in un nuovo array di byte che ha due byte aggiuntivi allocati all'inizio.

Lo stesso vale per la decodifica di tale stringa, ma questo è molto più semplice utilizzando il java.lang.String costruttore :

public String(byte[] bytes,
              int offset,
              int length,
              String charsetName)
È stato utile?

Soluzione

Il nome charset "UTF-16" sarà sempre codificare con una distinta base e decodifica i dati utilizzando piccolo grande endianness /, ma "UnicodeBig" e "UnicodeLittle" sono utili per la codifica in un ordine byte specifico. Utilizzare UTF-16 o UTF-16BE senza BOM - vedere questo post per come utilizzare '\ uFEFF' per gestire le distinte componenti manualmente. Vedere qui per la denominazione canonica di charset nomi stringa o (preferibilmente) il Charset class. Anche prendere atto che solo una sottoinsieme limitato di codifiche sono assolutamente necessari per essere supportati.

Altri suggerimenti

Questo è come si fa in nio:

    return Charset.forName("UTF-16LE").encode(message)
            .put(0, (byte) 0xFF)
            .put(1, (byte) 0xFE)
            .array();

E 'certamente dovrebbe essere più veloce, ma non so quanti array si fa sotto le coperte, ma la mia comprensione del punto di API è che si suppone per ridurre al minimo questo.

Prima di tutto, per la decodifica è possibile utilizzare il set di caratteri "UTF-16"; che rileva automaticamente una distinta iniziale. Per la codifica UTF-16 BE è anche possibile utilizzare il set di caratteri "UTF-16" - che scriverò un BOM corretta e roba poi uscita big endian

.

Per la codifica a little endian con una distinta base, non credo che il codice corrente è troppo male, anche con la doppia assegnazione (a meno che le corde siano veramente mostruosa). Che cosa si potrebbe desiderare di fare se sono non trattare con un array di byte, ma piuttosto una java.nio ByteBuffer, e utilizzare la classe java.nio.charset.CharsetEncoder. (Che si può ottenere da Charset.forName ( "UTF-16"). NewEncoder ()).

    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(string.length() * 2 + 2);
    byteArrayOutputStream.write(new byte[]{(byte)0xFF,(byte)0xFE});
    byteArrayOutputStream.write(string.getBytes("UTF-16LE"));
    return byteArrayOutputStream.toByteArray();

EDIT: Rileggendo la tua domanda, vedo si preferisce evitare l'assegnazione doppio array del tutto. Purtroppo l'API non ti dà che, per quanto ne so. (C'era un metodo, ma è deprecato, e non è possibile specificare la codifica con esso).

ho scritto quanto sopra, prima ho visto il tuo commento, credo che la risposta a utilizzare le classi Nio è sulla strada giusta. Stavo guardando, ma io non sono a conoscenza abbastanza con l'API di sapere fuori mano come ottenere che fare.

Questa è una vecchia questione, ma ancora, non riuscivo a trovare una risposta accettabile per la mia situazione. In sostanza, Java non dispone di un encoder incorporato per UTF-16 con una distinta. E così, si deve stendere la propria implementazione.

Ecco quello che ho finito con:

private byte[] encodeUTF16LEWithBOM(final String s) {
    ByteBuffer content = Charset.forName("UTF-16LE").encode(s);
    byte[] bom = { (byte) 0xff, (byte) 0xfe };
    return ByteBuffer.allocate(content.capacity() + bom.length).put(bom).put(content).array();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top