Konvertieren eines Byte-Arrays in einen String (Java)

85

Ich schreibe eine Webanwendung in der Google App Engine. Es ermöglicht den Benutzern, HTML-Code zu bearbeiten, der als .htmlDatei im Blobstore gespeichert wird.

Ich verwende fetchData, um eines byte[]der Zeichen in der Datei zurückzugeben. Ich versuche, in ein HTML zu drucken, damit der Benutzer den HTML-Code bearbeiten kann. Alles funktioniert super!

Hier ist jetzt mein einziges Problem:

Das Byte-Array weist beim Zurückkonvertieren in eine Zeichenfolge einige Probleme auf. Kluge Zitate und ein paar Charaktere sehen funky aus. (? 's oder japanische Symbole usw.) Insbesondere sehe ich mehrere Bytes mit negativen Werten, die das Problem verursachen.

Die intelligenten Anführungszeichen werden als -108und -109im Byte-Array zurückgegeben. Warum ist das so und wie kann ich die negativen Bytes dekodieren, um die richtige Zeichenkodierung anzuzeigen?

Josh
quelle
Duplikat von stackoverflow.com/questions/1536054/…
james.garriss
Hallo, ich weiß, dass es ein sehr alter Beitrag ist, aber ich stehe vor ähnlichen Problemen. Ich mache einen Man-in-the-Middle-Proxy für SSL. Das Problem, mit dem ich konfrontiert bin, ist dasselbe wie deins. Ich höre auf den Socket und bekomme die Daten rein InputStreamund dann rein byte[]. Wenn ich jetzt versuche, den byte[]in String umzuwandeln (ich muss den Antworttext für Angriffe verwenden), bekomme ich wirklich lustige Charaktere voller intelligenter Anführungszeichen und Fragezeichen und was nicht. Ich glaube , Ihr Problem wie meine gleiche ist , wie wir beide es zu tun htmlin byte[]. Können Sie mir bitte einen Rat geben?
Parul S
Übrigens habe ich die Codierung meines Systems mithilfe von Sytem.properties ermittelt und festgestellt, dass es sich um "Cp1252" handelt. Jetzt habe ich verwendetString str=new String(buffer, "Cp1252"); aber keine Hilfe benutzt.
Parul S

Antworten:

141

Das Byte-Array enthält Zeichen in einer speziellen Codierung (die Sie kennen sollten). Die Konvertierung in einen String ist wie folgt:

String decoded = new String(bytes, "UTF-8");  // example for one encoding type

Übrigens: Die angezeigten Rohbytes werden möglicherweise als negative Dezimalstellen angezeigt, nur weil der Java-Datentyp bytesigniert ist. Er deckt den Bereich von -128 bis 127 ab.


-109 = 0x93: Control Code "Set Transmit State"

Der Wert (-109) ist ein nicht druckbares Steuerzeichen in UNICODE. UTF-8 ist also nicht die richtige Codierung für diesen Zeichenstrom.

0x93in "Windows-1252" ist das "intelligente Zitat", das Sie suchen, daher lautet der Java-Name dieser Codierung "Cp1252". Die nächste Zeile enthält einen Testcode:

System.out.println(new String(new byte[]{-109}, "Cp1252")); 
Andreas Dolk
quelle
5
Ich habe versucht, UTF-8 zu verwenden, und es kam immer noch als? Heraus. Wie kommt es, dass für diese negativen Werte keine Zuordnung gefunden wird?
Josh
0x93 ist jedoch ein gültiges Fortsetzungsbyte in UTF-8 - das Vorhandensein dieses Bytes schließt nur aus, dass es UTF-8 ist, wenn es nicht nach einem Byte mit den ersten zwei gesetzten Bits kommt.
Nick Johnson
1
@ Josh Andreas erklärt warum - weil Javas byteDatentyp signiert ist. Die 'negativen' Werte sind nur Bytes mit dem höchstwertigen Bytesatz. Er erklärt auch, was der wahrscheinlichste Zeichensatz ist, den Sie verwenden sollten - Windows-1252. Sie sollten jedoch anhand des Kontexts oder der Konvention wissen, welchen Zeichensatz Sie verwenden müssen, ohne raten zu müssen.
Nick Johnson
25

Java 7 und höher

Sie können Ihre gewünschte Codierung auch Stringals CharsetKonstante von StandardCharsets an den Konstruktor übergeben . Dies kann sicherer sein, als die Codierung als zu übergeben String, wie in den anderen Antworten vorgeschlagen.

Zum Beispiel für die UTF-8-Codierung

String bytesAsString = new String(bytes, StandardCharsets.UTF_8);
davnicwil
quelle
1
Dies ist eine Wiederholung einer Antwort aus dem Jahr 2011. -1
james.garriss
2
@ james.garriss Ich glaube nicht, dass dies der Fall ist, da ich nur einen neuen Konstruktor erwähne, der in Java 7 eingeführt wurde und die Codierung als Konstante übergibt, was meiner Meinung nach schöner und sicherer ist als die vorherige API in den früheren Antworten erwähnt, in denen die Codierung, wenn überhaupt, als String übergeben wurde.
Davnicwil
11

Sie können dies versuchen.

String s = new String(bytearray);
Muhammad Aamir Ali
quelle
9
Sie können es versuchen ... aber es wird in fast allen Fällen fehlschlagen.
Raedwald
5
public class Main {

    /**
     * Example method for converting a byte to a String.
     */
    public void convertByteToString() {

        byte b = 65;

        //Using the static toString method of the Byte class
        System.out.println(Byte.toString(b));

        //Using simple concatenation with an empty String
        System.out.println(b + "");

        //Creating a byte array and passing it to the String constructor
        System.out.println(new String(new byte[] {b}));

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Main().convertByteToString();
    }
}

Ausgabe

65
65
A
Adi Sembiring
quelle
5
public static String readFile(String fn)   throws IOException 
{
    File f = new File(fn);

    byte[] buffer = new byte[(int)f.length()];
    FileInputStream is = new FileInputStream(fn);
    is.read(buffer);
    is.close();

    return  new String(buffer, "UTF-8"); // use desired encoding
}
Craig
quelle
3
Dieser Code leckt eine Ressource, wenn readeine Ausnahme ausgelöst wird.
Raedwald
4

Ich schlage vor Arrays.toString(byte_array);

Es hängt von Ihrem Zweck ab. Zum Beispiel wollte ich ein Byte-Array genau so speichern, wie Sie es zum Zeitpunkt des Debuggens sehen können. [1, 2, 3]Wenn Sie genau denselben Wert speichern möchten, ohne die Bytes in das Zeichenformat zu konvertieren, Arrays.toString (byte_array)tun Sie dies. Wenn Sie jedoch Zeichen anstelle von Bytes speichern möchten, sollten Sie verwenden String s = new String(byte_array). In diesem Fall sentspricht dies dem [1, 2, 3]Zeichenformat.

Fragesteller
quelle
Können Sie weitere Informationen darüber geben, warum Sie dies vorschlagen? (Wird es das Problem lösen? Können Sie sagen, warum es es löst?) Danke!
Dean J
Es hängt von Ihrem Zweck ab. Zum Beispiel wollte ich ein Byte-Array genau so speichern, wie es zum Zeitpunkt des Debuggens angezeigt wird: [1, 2, 3] Wenn Sie genau denselben Wert speichern möchten, ohne die Bytes in das Zeichenformat zu konvertieren, Arrays.toString (byte_array) erledigt dies. Wenn Sie jedoch Zeichen anstelle von Bytes speichern möchten, sollten Sie String s = new String (byte_array) verwenden. In diesem Fall entspricht s im Zeichenformat dem Äquivalent von [1, 2, 3].
Frager
@sas, Sie sollten diese Informationen zu Ihrer Antwort selbst hinzufügen (indem Sie sie bearbeiten) und nicht als Kommentar. Im Allgemeinen sollten Sie bei SO immer bedenken, dass Kommentare jederzeit gelöscht werden können - die wirklich wichtigen Informationen sollten in der Antwort selbst enthalten sein.
Jeen Broekstra
3

Die vorherige Antwort von Andreas_D ist gut. Ich möchte nur hinzufügen, dass überall dort, wo Sie die Ausgabe anzeigen, eine Schriftart und eine Zeichenkodierung vorhanden sind und einige Zeichen möglicherweise nicht unterstützt werden.

Gehen Sie folgendermaßen vor, um herauszufinden, ob Java oder Ihr Display ein Problem darstellt:

    for(int i=0;i<str.length();i++) {
        char ch = str.charAt(i);
        System.out.println(i+" : "+ch+" "+Integer.toHexString(ch)+((ch=='\ufffd') ? " Unknown character" : ""));
    }

Java hat alle Zeichen, die es nicht verstehen kann, dem offiziellen Zeichen für unbekannte Zeichen zugeordnet. Wenn Sie ein '?' In der Ausgabe, die jedoch nicht 0xfffd zugeordnet ist, ist Ihre Anzeigeschrift oder -codierung das Problem, nicht Java.

Simon G.
quelle