So konvertieren Sie Strings in und von UTF8-Byte-Arrays in Java

239

In Java habe ich einen String und möchte ihn als Byte-Array codieren (in UTF8 oder einer anderen Codierung). Alternativ habe ich ein Byte-Array (in einer bekannten Codierung) und möchte es in einen Java-String konvertieren. Wie mache ich diese Konvertierungen?

mcherm
quelle

Antworten:

355

Von String in Byte konvertieren []:

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

Von Byte [] in String konvertieren:

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

Sie sollten natürlich den richtigen Codierungsnamen verwenden. In meinen Beispielen wurden US-ASCII und UTF-8 verwendet, die beiden am häufigsten verwendeten Codierungen.

mcherm
quelle
30
US-ASCII ist heutzutage eigentlich keine sehr verbreitete Codierung. Windows-1252 und ISO-8859-1 (die Obermengen von ASCII sind) sind weitaus weiter verbreitet.
Michael Borgwardt
11
Eigentlich finde ich es ziemlich häufig in meiner Arbeit. Ich lese oft Byte-Streams, die möglicherweise als Windows-1252 oder ISO-8859-1 oder sogar nur als "Ausgabe dieses Legacy-Programms, das wir in den letzten 10 Jahren hatten" gespeichert wurden, aber Bytes enthalten, deren Gültigkeit garantiert ist US-ASCII-Zeichen. Ich habe auch oft die Anforderung, solche Dateien zu generieren (für den Verbrauch durch Code, der möglicherweise Nicht-ASCII-Zeichen verarbeiten kann oder nicht). Grundsätzlich ist US-ASCII der "größte gemeinsame Nenner" vieler Softwareteile.
Mcherm
1
Diese Methode meldet jedoch keine Probleme bei der Konvertierung. Dies kann sein, was Sie wollen. Wenn nicht, wird empfohlen, stattdessen CharsetEncoder zu verwenden.
Michael Piefel
7
@Pacerier, da in den Dokumenten für Zeichensatz "UTF-8" als einer der Standardzeichensätze aufgeführt ist. Ich glaube, dass Ihre Rechtschreibung auch akzeptiert wird, aber ich habe mich an das gehalten, was die Dokumente gesagt haben.
Mcherm
20
Seit JDK7 können Sie StandardCharsets.UTF_8 docs.oracle.com/javase/7/docs/api/java/nio/charset/…
Rafael Membrives
95

Hier ist eine Lösung, die es vermeidet, die Zeichensatzsuche für jede Konvertierung durchzuführen:

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);
}
Mike Leonhard
quelle
4
@mcherm: Auch wenn der Leistungsunterschied gering ist, bevorzuge ich, wenn möglich, Objekte (Zeichensatz, URL usw.) gegenüber ihren Zeichenfolgenformen.
Bart van Heukelom
7
Hinweis: "Seit 1.6" öffentlicher String (Byte [] Bytes, Zeichensatz Zeichensatz)
Leo
1
Bezüglich "Vermeidet die Durchführung der Zeichensatzsuche für jede Konvertierung" ... geben Sie bitte eine Quelle an. Ist java.nio.charset.Charset nicht gebaut auf der String.getBytes und hat daher mehr Aufwand als String.getBytes?
Pacerier
2
In den Dokumenten heißt es: "Das Verhalten dieser Methode, wenn diese Zeichenfolge nicht in dem angegebenen Zeichensatz codiert werden kann, ist nicht angegeben. Die CharsetEncoder-Klasse sollte verwendet werden, wenn mehr Kontrolle über den Codierungsprozess erforderlich ist."
Paiego
24
Hinweis: Seit Java 1.7 können Sie StandardCharsets.UTF_8für einen konstanten Zugriff auf den UTF-8-Zeichensatz verwenden.
Kat
17
String original = "hello world";
byte[] utf8Bytes = original.getBytes("UTF-8");
Jorge Ferreira
quelle
Vielen Dank! Ich habe es selbst noch einmal geschrieben und die andere Richtung der Bekehrung hinzugefügt.
Mcherm
1
@smink Der Bindestrich ist nicht optional. Dies sollte "UTF-8"
Mel Nicholson
14

Sie können direkt über den Konstruktor String (byte [], String) und die Methode getBytes (String) konvertieren. Java macht verfügbare Zeichensätze über die Charset- Klasse verfügbar . In der JDK-Dokumentation sind die unterstützten Codierungen aufgeführt .

In 90% der Fälle werden solche Konvertierungen in Streams durchgeführt, sodass Sie die Reader / Writer- Klassen verwenden würden. Sie würden nicht schrittweise mit den String-Methoden für beliebige Byte-Streams dekodieren - Sie würden sich für Fehler mit Multibyte-Zeichen offen lassen.

McDowell
quelle
Können Sie das näher erläutern? Wenn meine Anwendung Strings in codiert und decodiert UTF-8, was ist das Problem in Bezug auf Multibyte-Zeichen?
Raffian
@raffian Probleme können auftreten, wenn Sie nicht alle Zeichendaten auf einmal transformieren. Siehe hier für ein Beispiel.
McDowell
12

Meine Tomcat7-Implementierung akzeptiert Zeichenfolgen als ISO-8859-1. trotz des Inhaltstyps der HTTP-Anfrage. Die folgende Lösung hat bei mir funktioniert, als ich versucht habe, Zeichen wie 'é' richtig zu interpretieren.

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

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

Beim Versuch, die Zeichenfolge als US-ASCII zu interpretieren, wurden die Byteinformationen nicht korrekt interpretiert.

b1 = szP1.getBytes("US-ASCII");
System.out.println(b1.toString());
Paiego
quelle
8
Zu Ihrer Information, ab Java 7 können Sie Konstanten für Zeichensatznamen wie StandardCharSets.UTF_8und verwenden StandardCharSets.ISO_8859_1.
Basil Bourque
Ich habe meinen Tag gerettet und für die erste oben erwähnte Lösung absolut gut funktioniert.
Hassan Jamil
7

Alternativ können StringUtils von Apache Commons verwendet werden.

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

oder

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

Wenn Sie einen nicht standardmäßigen Zeichensatz haben, können Sie getBytesUnchecked () oder newString () entsprechend verwenden.

vtor
quelle
4
Beachten Sie, dass diese StringUtils aus dem Commons Codec stammen , nicht aus Commons Lang.
Arend v. Reinersdorff
Ja, ein bisschen gotcha! Für Benutzer von Gradle, Maven: "commons-codec: commons-codec: 1.10" (zum Zeitpunkt des Schreibens). Dies wird beispielsweise auch als Abhängigkeit vom Apache-POI gebündelt. Abgesehen davon Apache Commons zur Rettung, wie immer!
Mike Nagetier
2

Zum Dekodieren einer Reihe von Bytes in eine normale Zeichenfolgennachricht habe ich es endlich mit der UTF-8-Codierung mit diesem Code zum Laufen gebracht:

/* 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"));
}
Bouke Woudstra
quelle
1

Wenn Sie 7-Bit-ASCII oder ISO-8859-1 (ein erstaunlich verbreitetes Format) verwenden, müssen Sie keinen neuen java.lang.String erstellen . Es ist viel viel performanter, das Byte einfach in char umzuwandeln:

Vollständiges Arbeitsbeispiel:

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

Wenn Sie nicht mit extended-Zeichen wie Ä, Æ, A, C, I, E und können sicher sein , dass die einzigen übertragenen Werte sind von den ersten 128 Unicode - Zeichen, dann wird dieser Code auch Arbeit für UTF-8 und erweiterten ASCII (wie cp-1252).

Pacerier
quelle
1

Ich kann nicht kommentieren, möchte aber keinen neuen Thread starten. Aber das funktioniert nicht. Eine einfache Rundreise:

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

Ich würde b [] dasselbe Array vor und nach der Codierung benötigen, was es nicht ist (dies bezieht sich auf die erste Antwort).

jschober
quelle
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);
Ran Adler
quelle
Konvertiert String Entity 'query' in utf-8 oder erinnert es sich beim Anhängen der Entität nur daran?
SyntaxRules
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);
Nitish Raj Srivastava
quelle
0
Reader reader = new BufferedReader(
    new InputStreamReader(
        new ByteArrayInputStream(
            string.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));
Макс Даниленко
quelle
-9

schrecklich spät, aber ich bin gerade auf dieses Problem gestoßen und dies ist meine Lösung:

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 );
}
savio
quelle
2
Erstens handelt es sich nicht um eine Konvertierung, sondern um das Entfernen nicht druckbarer Bytes. Zweitens wird davon ausgegangen, dass die Standardcodierung des zugrunde liegenden Betriebssystems tatsächlich auf ASCII für druckbare Zeichen basiert (funktioniert beispielsweise bei IBM Mainframes mit EBCDIC nicht).
Isaac