Wie konvertiere ich ein Byte-Array in einen String und umgekehrt?

247

Ich muss ein Byte-Array in Android in einen String konvertieren, aber mein Byte-Array enthält negative Werte.

Wenn ich diese Zeichenfolge erneut in ein Byte-Array konvertiere, unterscheiden sich die Werte, die ich erhalte, von den ursprünglichen Byte-Array-Werten.

Was kann ich tun, um eine ordnungsgemäße Konvertierung zu erzielen? Der Code, den ich für die Konvertierung verwende, lautet wie folgt:

// Code to convert byte arr to str:
byte[] by_original = {0,1,-2,3,-4,-5,6};
String str1 = new String(by_original);
System.out.println("str1 >> "+str1);

// Code to convert str to byte arr:
byte[] by_new = str1.getBytes();
for(int i=0;i<by_new.length;i++) 
System.out.println("by1["+i+"] >> "+str1);

Ich stecke in diesem Problem fest.

Jyotsna
quelle
3
Warum versuchen Sie überhaupt, beliebige Binärdaten in einen String zu konvertieren? Abgesehen von all den Zeichensatzproblemen, die in den Antworten bereits erwähnt wurden, gibt es auch die Tatsache, dass Sie String missbrauchen, wenn Sie dies tun. Was ist falsch daran, a byte[]für Ihre Binärdaten und Stringfür Ihren Text zu verwenden?
Joachim Sauer
8
@ Joachim - manchmal haben Sie externe Tools, mit denen Sie beispielsweise Zeichenfolgen speichern können. In diesem Fall möchten Sie ein Byte-Array in eine (auf irgendeine Weise codierte) Zeichenfolge umwandeln können.
James Moore

Antworten:

377

Ihr Byte-Array muss eine Codierung haben. Die Codierung kann nicht ASCII sein, wenn Sie negative Werte haben. Sobald Sie das herausgefunden haben, können Sie eine Reihe von Bytes in einen String konvertieren, indem Sie:

byte[] bytes = {...}
String str = new String(bytes, "UTF-8"); // for UTF-8 encoding

Es gibt eine Reihe von Codierungen, die Sie verwenden können. Schauen Sie sich die Charset-Klasse in den Sun-Javadocs an .

Omerkudat
quelle
4
@MauricePerry kannst du erklären, warum es nicht funktioniert UTF-8?
Asif Mushtaq
12
@UnKnown, da UTF-8 einige Zeichen als 2- oder 3-Byte-Zeichenfolgen codiert. Nicht jedes Byte-Array ist eine gültige UTF-8-codierte Zeichenfolge. ISO-8859-1 wäre eine bessere Wahl: Hier wird jedes Zeichen als Byte codiert.
Maurice Perry
1
Dies könnte funktionieren, aber Sie sollten die Verwendung des String-Konstruktors um jeden Preis vermeiden.
Hfontanez
um ein Byte einem Zeichen zuzuordnen (mit 8859-1) und keine Ausnahmebehandlung (mit nio.charset):String str = new String(bytes, java.nio.charset.StandardCharsets.ISO_8859_1);
Iman
1
seit Java 1.7 können Sie neue
Zeichenfolge
101

Die "richtige Konvertierung" zwischen byte[]und Stringbesteht darin, die zu verwendende Codierung explizit anzugeben. Wenn Sie mit a beginnen byte[]und es tatsächlich keine Textdaten enthält, gibt es keine "ordnungsgemäße Konvertierung". Strings sind für Text, byte[]für Binärdaten, und das einzig wirklich Sinnvolle ist, die Konvertierung zwischen ihnen zu vermeiden , es sei denn, Sie müssen dies unbedingt tun .

Wenn Sie wirklich a verwenden müssen String, um Binärdaten zu speichern, ist die Verwendung der Base64- Codierung der sicherste Weg .

Michael Borgwardt
quelle
1
Ja, die Zeichencodierung müssen Sie kennen , um zwischen Zeichenfolgen und Bytes konvertieren zu können.
Raedwald
4
Base64 und du hast mein Leben gerettet
mstzn
2
Die Base64-Codierung hat mein Problem gelöst. UTF-8 funktionierte nicht für alle Eingaben
Al-Alamin
37

Das Grundproblem ist (glaube ich), dass Sie unabsichtlich einen Zeichensatz verwenden, für den:

 bytes != encode(decode(bytes))

in manchen Fällen. UTF-8 ist ein Beispiel für einen solchen Zeichensatz. Insbesondere sind bestimmte Folgen von Bytes keine gültigen Codierungen in UTF-8. Wenn der UTF-8-Decoder auf eine dieser Sequenzen stößt, kann er die fehlerhaften Bytes verwerfen oder als Unicode-Codepunkt für "kein solches Zeichen" decodieren. Wenn Sie dann versuchen, die Zeichen als Bytes zu codieren, ist das Ergebnis natürlich anders.

Die Lösung ist:

  1. Geben Sie die von Ihnen verwendete Zeichenkodierung an. Verwenden Sie also einen String-Konstruktor und eine String- String.toByteArrayMethode mit einem expliziten Zeichensatz.
  2. Verwenden Sie den richtigen Zeichensatz für Ihre Byte-Daten ... oder alternativ einen (z. B. "Latin-1", bei dem alle Byte-Sequenzen gültigen Unicode-Zeichen zugeordnet sind.
  3. Wenn Ihre Bytes (wirklich) Binärdaten sind und Sie sie über einen "textbasierten" Kanal senden / empfangen möchten, verwenden Sie eine Base64-Codierung ..., die für diesen Zweck entwickelt wurde .
Stephen C.
quelle
1
Vielen Dank für den Tipp zur Verwendung der "Latin-1" -Codierung!
Gonzo
31

Wir müssen nur ein neues Stringmit dem Array erstellen: http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

String s = new String(bytes);

Die Bytes der resultierenden Zeichenfolge unterscheiden sich je nachdem, welchen Zeichensatz Sie verwenden. Der neue String (Bytes) und der neue String (Bytes, Charset.forName ("utf-8")) sowie der neue String (Bytes, Charset.forName ("utf-16")) haben alle unterschiedliche Byte-Arrays, wenn Sie String # aufrufen getBytes () (abhängig vom Standardzeichensatz)

Ravindranath Akila
quelle
9
Nein. Die Bytes der resultierenden Zeichenfolge unterscheiden sich je nachdem, welchen Zeichensatz Sie verwenden. new String(bytes)und new String(bytes, Charset.forName("utf-8"))und new String(bytes, Charset.forName("utf-16"))alle haben unterschiedliche Byte-Arrays, wenn Sie aufrufen String#getBytes()(abhängig vom Standard-Zeichensatz)
NS du Toit
1
Irreführend. Das chars (und damit der angezeigte Text) des Ergebnisses Stringunterscheidet sich bei der Dekodierung bytesunterschiedlich. Die Konvertierung zurück in Bytes unter Verwendung der Standardcodierung (verwenden Sie String#getBytes("charset"), um etwas anderes anzugeben) unterscheidet sich notwendigerweise, da unterschiedliche Eingaben konvertiert werden. Strings speichern nicht die, aus denen byte[]sie gemacht wurden, chars haben keine Codierung und a Stringspeichert sie nicht anders.
Zapl
14

Das Verwenden new String(byOriginal)und Zurückkonvertieren in das byte[]Verwenden getBytes()garantiert nicht zwei byte[]mit gleichen Werten. Dies ist auf einen Aufruf zurückzuführen, StringCoding.encode(..)der das Stringto codiert Charset.defaultCharset(). Während dieser Codierung kann der Codierer unbekannte Zeichen ersetzen und andere Änderungen vornehmen. Daher gibt using String.getBytes()möglicherweise nicht das gleiche Array zurück, wie Sie es ursprünglich an den Konstruktor übergeben haben.

sfussenegger
quelle
9

Warum war das Problem: Wie bereits jemand angegeben: Wenn Sie mit einem Byte [] beginnen und es tatsächlich keine Textdaten enthält, gibt es keine "richtige Konvertierung". Zeichenfolgen sind für Text, Byte [] für Binärdaten, und das einzig wirklich Sinnvolle ist, die Konvertierung zwischen ihnen zu vermeiden, es sei denn, Sie müssen dies unbedingt tun.

Ich habe dieses Problem beobachtet, als ich versucht habe, Byte [] aus einer PDF-Datei zu erstellen, es dann in einen String zu konvertieren und dann den String als Eingabe zu nehmen und wieder in eine Datei zu konvertieren.

Stellen Sie also sicher, dass Ihre Kodierungs- und Dekodierungslogik mit meiner identisch ist. Ich habe das Byte [] explizit in Base64 codiert und dekodiert, um die Datei erneut zu erstellen.

Use-Case: Aufgrund einiger Einschränkung Ich habe versucht , zu abgeschickt byte[]in request(POST)und das Verfahren war wie folgt:

PDF-Datei >> Base64.encodeBase64 (Byte []) >> String >> Anfrage senden (POST) >> String empfangen >> Base64.decodeBase64 (Byte []) >> Binärdatei erstellen

Versuchen Sie dies und das hat bei mir funktioniert ..

File file = new File("filePath");

        byte[] byteArray = new byte[(int) file.length()];

        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            fileInputStream.read(byteArray);

            String byteArrayStr= new String(Base64.encodeBase64(byteArray));

            FileOutputStream fos = new FileOutputStream("newFilePath");
            fos.write(Base64.decodeBase64(byteArrayStr.getBytes()));
            fos.close();
        } 
        catch (FileNotFoundException e) {
            System.out.println("File Not Found.");
            e.printStackTrace();
        }
        catch (IOException e1) {
            System.out.println("Error Reading The File.");
            e1.printStackTrace();
        }
Rupesh
quelle
6

Das funktioniert gut für mich:

String cd="Holding some value";

Konvertieren von Zeichenfolge in Byte []:

byte[] cookie = new sun.misc.BASE64Decoder().decodeBuffer(cd);

Konvertieren von Byte [] in Zeichenfolge:

cd = new sun.misc.BASE64Encoder().encode(cookie);
LED
quelle
5
private static String toHexadecimal(byte[] digest){
        String hash = "";
    for(byte aux : digest) {
        int b = aux & 0xff;
        if (Integer.toHexString(b).length() == 1) hash += "0";
        hash += Integer.toHexString(b);
    }
    return hash;
}
sdelvalle57
quelle
Dies beantwortet die Frage nicht.
James.garriss
Beantwortet die Frage nicht, war aber nützlich +1
Lazy Ninja
5

Ich habe etwas bemerkt, das in keiner der Antworten enthalten ist. Sie können jedes der Bytes im Byte-Array in Zeichen umwandeln und in ein char-Array einfügen. Dann ist die Zeichenfolge

new String(cbuf)
Dabei ist cbuf das char-Array. Um zurück zu konvertieren, durchlaufen Sie die Zeichenfolge, die jedes der Zeichen in Bytes umwandelt, um sie in ein Byte-Array einzufügen. Dieses Byte-Array ist das gleiche wie das erste.


public class StringByteArrTest {

    public static void main(String[] args) {
        // put whatever byte array here
        byte[] arr = new byte[] {-12, -100, -49, 100, -63, 0, -90};
        for (byte b: arr) System.out.println(b);
        // put data into this char array
        char[] cbuf = new char[arr.length];
        for (int i = 0; i < arr.length; i++) {
            cbuf[i] = (char) arr[i];
        }
        // this is the string
        String s = new String(cbuf);
        System.out.println(s);

        // converting back
        byte[] out = new byte[s.length()];
        for (int i = 0; i < s.length(); i++) {
            out[i] = (byte) s.charAt(i);
        }
        for (byte b: out) System.out.println(b);
    }

}
Leonid
quelle
2

javax.xml.bind.DatatypeConverter Sollte es tun:

byte [] b = javax.xml.bind.DatatypeConverter.parseHexBinary("E62DB");
String s = javax.xml.bind.DatatypeConverter.printHexBinary(b);
Wolfgang Kaisers
quelle
2

Hier sind einige Methoden, die ein Array von Bytes in eine Zeichenfolge konvertieren. Ich habe sie getestet, sie funktionieren gut.

public String getStringFromByteArray(byte[] settingsData) {

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(settingsData);
    Reader reader = new BufferedReader(new InputStreamReader(byteArrayInputStream));
    StringBuilder sb = new StringBuilder();
    int byteChar;

    try {
        while((byteChar = reader.read()) != -1) {
            sb.append((char) byteChar);
        }
    }
    catch(IOException e) {
        e.printStackTrace();
    }

    return sb.toString();

}

public String getStringFromByteArray(byte[] settingsData) {

    StringBuilder sb = new StringBuilder();
    for(byte willBeChar: settingsData) {
        sb.append((char) willBeChar);
    }

    return sb.toString();

}
user2288580
quelle
2

Obwohl

new String(bytes, "UTF-8")

ist richtig, es wirft ein, UnsupportedEncodingExceptionwas Sie zwingt, mit einer aktivierten Ausnahme umzugehen. Sie können alternativ einen anderen Konstruktor seit Java 1.6 verwenden, um ein Byte-Array in Folgendes zu konvertieren String:

new String(bytes, StandardCharsets.UTF_8)

Dieser wirft keine Ausnahme.

Das Zurückkonvertieren sollte auch erfolgen mit StandardCharsets.UTF_8:

"test".getBytes(StandardCharsets.UTF_8)

Auch hier müssen Sie sich nicht mit geprüften Ausnahmen befassen.

gil.fernandes
quelle
1

Mit dieser Methode konnte ich das Byte-Array in einen String konvertieren:

public static String byteArrayToString(byte[] data){
    String response = Arrays.toString(data);

    String[] byteValues = response.substring(1, response.length() - 1).split(",");
    byte[] bytes = new byte[byteValues.length];

    for (int i=0, len=bytes.length; i<len; i++) {
        bytes[i] = Byte.parseByte(byteValues[i].trim());
    }

    String str = new String(bytes);
    return str.toLowerCase();
}
lxknvlk
quelle
1

Während die Base64-Codierung sicher ist und man "die richtige Antwort" argumentieren könnte, bin ich hier angekommen und habe nach einer Möglichkeit gesucht, ein Java-Byte-Array so wie es ist in einen Java-String zu konvertieren. Das heißt, wo jedes Mitglied des Byte-Arrays in seinem String-Gegenstück intakt bleibt, ohne dass zusätzlicher Speicherplatz für die Codierung / den Transport erforderlich ist.

Diese Antwort , die transparente 8-Bit-Codierungen beschreibt, war für mich sehr hilfreich. Ich habe ISO-8859-1Terabyte an Binärdaten verwendet, um erfolgreich hin und her zu konvertieren (binäre <-> Zeichenfolge), ohne den für eine Base64-Codierung erforderlichen überhöhten Speicherplatzbedarf zu haben. Dies ist für meinen Anwendungsfall - YMMV - sicher.

Dies war auch hilfreich, um zu erklären, wann / ob Sie experimentieren sollten.

Reed Sandberg
quelle
0
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;    

private static String base64Encode(byte[] bytes)
{
    return new BASE64Encoder().encode(bytes);
}

private static byte[] base64Decode(String s) throws IOException
{
    return new BASE64Decoder().decodeBuffer(s);
}
Feng Zhang
quelle
Warum? Warum sollte Base64 durchlaufen werden, um ein Byte in einen String zu konvertieren? Der Overhead.
James.garriss
0

Hier der Arbeitscode.

            // Encode byte array into string . TemplateBuffer1 is my bytearry variable.

        String finger_buffer = Base64.encodeToString(templateBuffer1, Base64.DEFAULT);
        Log.d(TAG, "Captured biometric device->" + finger_buffer);


        // Decode String into Byte Array. decodedString is my bytearray[] 
        decodedString = Base64.decode(finger_buffer, Base64.DEFAULT);
Sudharsan Chandrasekaran
quelle
-1

Versuchen Sie, in beiden Konvertierungen einen 8-Bit-Zeichensatz anzugeben. Zum Beispiel ISO-8859-1.

Maurice Perry
quelle
-1

Lesen Sie die Bytes aus der StringVerwendung ByteArrayInputStreamund umschließen Sie sie mit BufferedReaderChar Stream anstelle von Byte Stream, der die Bytedaten in String konvertiert.

package com.cs.sajal;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

public class TestCls {

    public static void main(String[] args) {

        String s=new String("Sajal is  a good boy");

        try
        {
        ByteArrayInputStream bis;
        bis=new ByteArrayInputStream(s.getBytes("UTF-8"));

        BufferedReader br=new BufferedReader(new InputStreamReader(bis));
        System.out.println(br.readLine());

        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

    }
}

Ausgabe ist:

Sajal ist ein guter Junge

Sajal Goyal
quelle
-1

Sie können die einfache for-Schleife für die Konvertierung verwenden:

public void byteArrToString(){
   byte[] b = {'a','b','$'};
   String str = ""; 
   for(int i=0; i<b.length; i++){
       char c = (char) b[i];
       str+=c;
   }
   System.out.println(str);
}
amoljdv06
quelle
-2
InputStream is = new FileInputStream("/home/kalt/Desktop/SUDIS/READY/ds.bin");
byte[] bytes = IOUtils.toByteArray(is);
Дмитрий Колтович
quelle
-3

Ein String ist eine Sammlung von Zeichen (16 Bit ohne Vorzeichen). Wenn Sie also negative Zahlen in eine Zeichenfolge konvertieren, gehen diese bei der Übersetzung verloren.

Kröte
quelle
1
-1: Das ist falsch. Während 'Byte' in Java ein vorzeichenbehafteter Typ ist, werden sie vom Bibliothekscode, der die Zeichensatzkodierung und -decodierung durchführt, als vorzeichenlos behandelt.
Stephen C
Ein gutes Beispiel, warum ein vorzeichenloser 8-Bit-Datentyp in einer Sprache wirklich eine gute Idee ist. Vermeidet unnötige Verwirrung; ^)
Kröte
Seien Sie vorsichtig bei der Annahme, dass ein Java-Zeichen 16 Bit groß sein wird. Aufgrund von Javas UTF-16 können sie auf bis zu 32 Bit erweitert werden
Joe Plante
1
@Toad tatsächlich ja, einige Unicode-Zeichen, wenn sie als UTF-16 gespeichert sind, belegen zwei Codepunkte, dh 32 Bit. Das gleiche passiert in UTF-8: Einige Zeichen verwenden zwei / drei / vier Codepunkte, dh 16/24/32 Bits. Genau darum geht es bei UTF (dh UTF! = Unicode).
CAFxX
1
@Toad Sie würden den ersten Ersatz bekommen - dh nur die erste "Hälfte" des Charakters. In den Dokumenten finden Sie die String.charAt- Methode und die Character- Klasse.
CAFxX
-3
public class byteString {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        String msg = "Hello";
        byte[] buff = new byte[1024];
        buff = msg.getBytes("UTF-8");
        System.out.println(buff);
        String m = new String(buff);
        System.out.println(m);


    }

}
Shyam Sreenivasan
quelle
Übergeben Sie die Zeichensatzcodierung als Argument an getBytes
Shyam Sreenivasan
1
Möglicherweise möchten Sie diese Antwort zusätzlich zum Code mit einer Erklärung versehen.
Charlie Schliesser