UTF-8 Byte [] zu String

243

Nehmen wir an, ich habe gerade a verwendet BufferedInputStream, um die Bytes einer UTF-8-codierten Textdatei in ein Byte-Array zu lesen. Ich weiß, dass ich die folgende Routine verwenden kann, um die Bytes in eine Zeichenfolge zu konvertieren. Gibt es jedoch eine effizientere / intelligentere Methode, als nur die Bytes zu durchlaufen und jedes einzelne zu konvertieren?

public String openFileToString(byte[] _bytes)
{
    String file_string = "";

    for(int i = 0; i < _bytes.length; i++)
    {
        file_string += (char)_bytes[i];
    }

    return file_string;    
}
Skeryl
quelle
17
Warum kannst du das nicht einfach machen String fileString = new String(_bytes,"UTF-8");?
CoolBeans
1
Alternativ können Sie BufferedReader verwenden, um in ein char-Array einzulesen.
Andy Thomas
@CoolBeans Ich könnte, wenn ich das gewusst hätte;) Danke.
Skeryl
Abhängig von der Dateigröße bin ich mir nicht sicher, ob das Laden des gesamten byte[]Speichers und das Konvertieren über new String(_bytes,"UTF-8")(oder sogar durch Chunks mit +=der Zeichenfolge) am effizientesten ist. Das Verketten von InputStreams und Readern funktioniert möglicherweise besser, insbesondere bei großen Dateien.
Bruno

Antworten:

498

Schauen Sie sich den Konstruktor für String an

String str = new String(bytes, StandardCharsets.UTF_8);

Und wenn Sie sich faul fühlen, können Sie den InputStream mithilfe der Apache Commons IO- Bibliothek direkt in einen String konvertieren:

String str = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
Jason Nichols
quelle
13
Oder Guavas Charsets.UTF_8, wenn Sie auf JDK älter als 1.7 sind
siledh
6
Verwenden Sie Guavas Charsets.UTF_8, wenn Sie auch auf Android API unter 19 sind
Ben Clayton
Und wenn checkstyle sagt: "Illegale Instanziierung: Die Instanziierung von java.lang.String sollte vermieden werden.", Was dann?
Attila Neparáczki
1
Sie können hier in der java.nio.charset.Charset.availableCharsets()Karte alle Zeichensätze sehen, nicht nur die Zeichensätze in der StandardCharsets. Und wenn Sie einen anderen Zeichensatz verwenden möchten und dennoch verhindern möchten, dass der String-Konstruktor UnsupportedEncodingExceptionjava.nio.charset.Charset.forName()
ausgelöst wird,
2
IOUtils.toString (inputStream, StandardCharsets.UTF_8) ist jetzt veraltet.
Aung Myat Hein
41

Die Java String-Klasse verfügt über einen integrierten Konstruktor zum Konvertieren eines Byte-Arrays in einen String.

byte[] byteArray = new byte[] {87, 79, 87, 46, 46, 46};

String value = new String(byteArray, "UTF-8");
Kashif Khan
quelle
9

Um utf-8-Daten zu konvertieren, können Sie keine 1-1-Entsprechung zwischen Bytes und Zeichen annehmen. Versuche dies:

String file_string = new String(bytes, "UTF-8");

(Bah. Ich sehe, ich bin viel zu langsam, wenn ich auf die Schaltfläche "Antwort posten" drücke.)

Gehen Sie folgendermaßen vor, um eine gesamte Datei als Zeichenfolge zu lesen:

public String openFileToString(String fileName) throws IOException
{
    InputStream is = new BufferedInputStream(new FileInputStream(fileName));

    try {
        InputStreamReader rdr = new InputStreamReader(is, "UTF-8");
        StringBuilder contents = new StringBuilder();
        char[] buff = new char[4096];
        int len = rdr.read(buff);
        while (len >= 0) {
            contents.append(buff, 0, len);
        }
        return buff.toString();
    } finally {
        try {
            is.close();
        } catch (Exception e) {
            // log error in closing the file
        }
    }
}
Ted Hopp
quelle
4

Sie können den String(byte[] bytes) Konstruktor dafür verwenden. Siehe diesen Link für Details. BEARBEITEN Sie müssen auch den Standardzeichensatz Ihrer Plattenform gemäß dem Java-Dokument berücksichtigen:

Erstellt einen neuen String, indem das angegebene Bytearray mit dem Standardzeichensatz der Plattform dekodiert wird. Die Länge des neuen Strings ist eine Funktion des Zeichensatzes und entspricht daher möglicherweise nicht der Länge des Bytearrays. Das Verhalten dieses Konstruktors, wenn die angegebenen Bytes im Standardzeichensatz nicht gültig sind, ist nicht angegeben. Die CharsetDecoder-Klasse sollte verwendet werden, wenn mehr Kontrolle über den Decodierungsprozess erforderlich ist.

GETah
quelle
1
Wenn sich Ihre Bytes nicht im Standardzeichensatz der Plattform befinden, können Sie die Version mit dem zweiten CharsetArgument verwenden, um sicherzustellen, dass die Konvertierung korrekt ist.
Mike Daniels
1
@ MikeDaniels In der Tat wollte ich nicht alle Details einschließen. Ich habe gerade meine Antwort bearbeitet
GETah
2

Wenn Sie wissen, dass es sich um ein UTF-8-Byte-Array handelt, sollten Sie auf jeden Fall den String-Konstruktor verwenden, der einen Zeichensatznamen akzeptiert . Andernfalls können Sie sich einigen Sicherheitslücken auf der Basis von Zeichensatzcodierung aussetzen. Beachten Sie, dass es wirft, mit UnsupportedEncodingExceptiondenen Sie umgehen müssen. Etwas wie das:

public String openFileToString(String fileName) {
    String file_string;
    try {
        file_string = new String(_bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        // this should never happen because "UTF-8" is hard-coded.
        throw new IllegalStateException(e);
    }
    return file_string;
}
Asaph
quelle
2

Hier ist eine vereinfachte Funktion, die Bytes einliest und eine Zeichenfolge erstellt. Es wird davon ausgegangen, dass Sie wahrscheinlich bereits wissen, in welcher Codierung sich die Datei befindet (und ansonsten standardmäßig).

static final int BUFF_SIZE = 2048;
static final String DEFAULT_ENCODING = "utf-8";

public static String readFileToString(String filePath, String encoding) throws IOException {

    if (encoding == null || encoding.length() == 0)
        encoding = DEFAULT_ENCODING;

    StringBuffer content = new StringBuffer();

    FileInputStream fis = new FileInputStream(new File(filePath));
    byte[] buffer = new byte[BUFF_SIZE];

    int bytesRead = 0;
    while ((bytesRead = fis.read(buffer)) != -1)
        content.append(new String(buffer, 0, bytesRead, encoding));

    fis.close();        
    return content.toString();
}
Scottt
quelle
Der Code wurde so bearbeitet, dass der Standardwert utf-8 ist und der Frage des OP entspricht.
Scottt
1

String hat einen Konstruktor, der Byte [] und Zeichensatznamen als Parameter verwendet :)

Soulcheck
quelle
0

Dies beinhaltet auch das Iterieren, aber dies ist viel besser als das Verketten von Zeichenfolgen, da diese sehr, sehr kostspielig sind.

public String openFileToString(String fileName)
{
    StringBuilder s = new StringBuilder(_bytes.length);

    for(int i = 0; i < _bytes.length; i++)
    {
        s.append((char)_bytes[i]);
    }

    return s.toString();    
}
Prahler
quelle
8
Mein lieber Herr. String str = new String(byte[])wird gut tun.
Zengr
3
Dies verbessert die Effizienz, dekodiert jedoch die utf8-Daten nicht richtig.
Ted Hopp
0

Warum nicht gleich von Anfang an das bekommen, wonach Sie suchen, und statt eines Arrays von Bytes einen String aus der Datei lesen? Etwas wie:

BufferedReader in = new BufferedReader(new InputStreamReader( new FileInputStream( "foo.txt"), Charset.forName( "UTF-8"));

dann readLine von in bis es fertig ist.

digitaljoel
quelle
Manchmal ist es nützlich, die ursprünglichen Zeilenbegrenzer beizubehalten. Das OP könnte das wollen.
Bruno
0

Ich benutze diesen Weg

String strIn = new String(_bytes, 0, numBytes);

Anatoliy Pelepetz
quelle
1
Dies gibt keinen Zeichensatz an, sodass Sie den Plattform-Standardzeichensatz erhalten, der möglicherweise nicht UTF-8 ist.
Greg-449