Come convertire stringhe da e verso array di byte UTF8 in Java


239

In Java, ho una stringa e voglio codificarla come array di byte (in UTF8 o qualche altra codifica). In alternativa, ho un array di byte (in alcune codifiche conosciute) e voglio convertirlo in una stringa Java. Come posso fare queste conversioni?

Risposte:


355

Converti da String a byte []:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);

Converti da byte [] a String:

byte[] b = {(byte) 99, (byte)97, (byte)116};
String s = new String(b, StandardCharsets.US_ASCII);

Ovviamente dovresti usare il nome di codifica corretto. I miei esempi hanno usato US-ASCII e UTF-8, le due codifiche più comuni.


30
Al giorno d'oggi US-ASCII non è una codifica molto comune. Windows-1252 e ISO-8859-1 (che sono superset di ASCII) sono molto più diffusi.
Michael Borgwardt,

11
In realtà, lo trovo abbastanza comune nel mio lavoro. Leggo spesso flussi di byte che potrebbero essere stati salvati come Windows-1252 o ISO-8859-1 o anche solo come "output di quel programma legacy che abbiamo avuto negli ultimi 10 anni", ma che contengono byte garantiti per essere validi Caratteri US-ASCII. Ho anche spesso l'obbligo di GENERARE tali file (per il consumo per codice che può o non può essere in grado di gestire caratteri non ASCII. Fondamentalmente, US-ASCII è il "massimo comune denominatore" di molti software.
mcherm,

1
Questo metodo, tuttavia, non segnalerà alcun problema nella conversione. Questo potrebbe essere quello che vuoi. In caso contrario, si consiglia di utilizzare CharsetEncoder.
Michael Piefel,

7
@Pacerier perché i documenti per Charset elencano "UTF-8" come uno dei set di caratteri standard. Credo che anche la tua ortografia sia accettata, ma sono andato con quello che dicevano i documenti.
mcherm,

20
Dal JDK7 è possibile utilizzare StandardCharsets.UTF_8 docs.oracle.com/javase/7/docs/api/java/nio/charset/…
Rafael Membrives,

95

Ecco una soluzione che evita di eseguire la ricerca Charset per ogni conversione:

import java.nio.charset.Charset;

private final Charset UTF8_CHARSET = Charset.forName("UTF-8");

String decodeUTF8(byte[] bytes) {
    return new String(bytes, UTF8_CHARSET);
}

byte[] encodeUTF8(String string) {
    return string.getBytes(UTF8_CHARSET);
}

4
@mcherm: anche se la differenza di prestazioni è piccola, preferisco usare oggetti (Charset, URL, ecc.) sui loro moduli di stringa, quando possibile.
Bart van Heukelom il

7
Nota: stringa pubblica "Since 1.6" (byte [] byte, set di caratteri Charset)
leo

1
Per quanto riguarda "evita di eseguire la ricerca Charset per ogni conversione" ... cita qualche fonte. Java.nio.charset.Charset non è costruito sopra String.getBytes e quindi ha un sovraccarico maggiore di String.getBytes?
Pacerier,

2
I documenti dichiarano: "Il comportamento di questo metodo quando questa stringa non può essere codificata nel set di caratteri specificato non è specificato. La classe CharsetEncoder deve essere utilizzata quando è richiesto un maggiore controllo sul processo di codifica."
paiego

24
Nota: da Java 1.7, è possibile utilizzare StandardCharsets.UTF_8per un modo costante di accedere al set di caratteri UTF-8.
Kat,

17
String original = "hello world";
byte[] utf8Bytes = original.getBytes("UTF-8");

Grazie! L'ho scritto di nuovo io stesso aggiungendo l'altra direzione della conversione.
mcherm,

1
@smink Il trattino non è facoltativo. Questo dovrebbe usare "UTF-8"
Mel Nicholson il

14

È possibile convertire direttamente tramite il costruttore String (byte [], String) e il metodo getBytes (String). Java espone i set di caratteri disponibili tramite la classe Charset . La documentazione JDK elenca le codifiche supportate .

Il 90% delle volte, tali conversioni vengono eseguite su stream, quindi utilizzeresti le classi Reader / Writer . Non decodificheresti in modo incrementale utilizzando i metodi String su flussi di byte arbitrari: ti lasceresti aperto ai bug che coinvolgono caratteri multibyte.


Puoi elaborare? Se la mia applicazione codifica e decodifica le stringhe UTF-8, qual è la preoccupazione per i caratteri multibyte?
Raffian,

@raffian Possono verificarsi problemi se non trasformi tutti i dati dei personaggi in una volta sola. Vedi qui per un esempio.
McDowell,

12

La mia implementazione tomcat7 accetta stringhe come ISO-8859-1; nonostante il tipo di contenuto della richiesta HTTP. La seguente soluzione ha funzionato per me quando ho cercato di interpretare correttamente personaggi come 'é'.

byte[] b1 = szP1.getBytes("ISO-8859-1");
System.out.println(b1.toString());

String szUT8 = new String(b1, "UTF-8");
System.out.println(szUT8);

Quando si tenta di interpretare la stringa come US-ASCII, le informazioni sui byte non sono state interpretate correttamente.

b1 = szP1.getBytes("US-ASCII");
System.out.println(b1.toString());

8
Cordiali saluti, a partire da Java 7 è possibile utilizzare le costanti per quei nomi di set di caratteri come StandardCharSets.UTF_8e StandardCharSets.ISO_8859_1.
Basil Bourque,

Mi ha salvato la giornata, lavorando perfettamente per la prima soluzione menzionata sopra.
Hassan Jamil,

7

In alternativa, è possibile utilizzare StringUtils di Apache Commons.

 byte[] bytes = {(byte) 1};
 String convertedString = StringUtils.newStringUtf8(bytes);

o

 String myString = "example";
 byte[] convertedBytes = StringUtils.getBytesUtf8(myString);

Se si dispone di set di caratteri non standard, è possibile utilizzare getBytesUnchecked () o newString () di conseguenza.


4
Nota che questo StringUtils di Commons Codec , non Commons Lang.
Arend v. Reinersdorff,

Sì, un po 'di gotcha! Per gli utenti Gradle, Maven: "commons-codec: commons-codec: 1.10" (al momento della stesura). Questo viene anche fornito in bundle come dipendenza dal PDI di Apache, ad esempio. A parte questo Apache Commons in soccorso, come sempre!
mike rodent,

2

Per decodificare una serie di byte in un normale messaggio stringa, ho finalmente funzionato con la codifica UTF-8 con questo codice:

/* Convert a list of UTF-8 numbers to a normal String
 * Usefull for decoding a jms message that is delivered as a sequence of bytes instead of plain text
 */
public String convertUtf8NumbersToString(String[] numbers){
    int length = numbers.length;
    byte[] data = new byte[length];

    for(int i = 0; i< length; i++){
        data[i] = Byte.parseByte(numbers[i]);
    }
    return new String(data, Charset.forName("UTF-8"));
}

1

Se si utilizza ASCII a 7 bit o ISO-8859-1 (un formato incredibilmente comune), non è necessario creare un nuovo java.lang.String . È molto più performante semplicemente trasmettere il byte in char:

Esempio di lavoro completo:

for (byte b : new byte[] { 43, 45, (byte) 215, (byte) 247 }) {
    char c = (char) b;
    System.out.print(c);
}

Se non si utilizzano caratteri estesi come Ä, Æ, Å, Ç, Ï, Ê e si può essere certi che gli unici valori trasmessi siano dei primi 128 caratteri Unicode, questo codice funzionerà anche per UTF-8 e ASCII esteso (come cp-1252).


1

Non posso commentare ma non voglio iniziare una nuova discussione. Ma questo non funziona. Un semplice viaggio di andata e ritorno:

byte[] b = new byte[]{ 0, 0, 0, -127 };  // 0x00000081
String s = new String(b,StandardCharsets.UTF_8); // UTF8 = 0x0000, 0x0000,  0x0000, 0xfffd
b = s.getBytes(StandardCharsets.UTF_8); // [0, 0, 0, -17, -65, -67] 0x000000efbfbd != 0x00000081

Avrei bisogno di b [] lo stesso array prima e dopo la codifica che non è (questo fa riferimento alla prima risposta).


0
//query is your json   

 DefaultHttpClient httpClient = new DefaultHttpClient();
 HttpPost postRequest = new HttpPost("http://my.site/test/v1/product/search?qy=");

 StringEntity input = new StringEntity(query, "UTF-8");
 input.setContentType("application/json");
 postRequest.setEntity(input);   
 HttpResponse response=response = httpClient.execute(postRequest);

String Entity converte 'query' in utf-8 o ricorda semplicemente quando si collega l'entità?
Sintassi Regole

0
Charset UTF8_CHARSET = Charset.forName("UTF-8");
String strISO = "{\"name\":\"א\"}";
System.out.println(strISO);
byte[] b = strISO.getBytes();
for (byte c: b) {
    System.out.print("[" + c + "]");
}
String str = new String(b, UTF8_CHARSET);
System.out.println(str);

0
Reader reader = new BufferedReader(
    new InputStreamReader(
        new ByteArrayInputStream(
            string.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));

-9

terribilmente in ritardo ma ho appena riscontrato questo problema e questa è la mia soluzione:

private static String removeNonUtf8CompliantCharacters( final String inString ) {
    if (null == inString ) return null;
    byte[] byteArr = inString.getBytes();
    for ( int i=0; i < byteArr.length; i++ ) {
        byte ch= byteArr[i]; 
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        if ( !( (ch > 31 && ch < 253 ) || ch == '\t' || ch == '\n' || ch == '\r') ) {
            byteArr[i]=' ';
        }
    }
    return new String( byteArr );
}

2
Innanzitutto, non è una conversione: è la rimozione di byte non stampabili. In secondo luogo, presuppone che la codifica predefinita del sistema operativo sottostante sia realmente basata su ASCII per i caratteri stampabili (ad esempio, non funzionerà sui mainframe IBM utilizzando EBCDIC).
Isaac,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.