Come convertire array di byte in stringa e viceversa?


248

Devo convertire un array di byte in stringa in Android, ma il mio array di byte contiene valori negativi.

Se converto di nuovo quella stringa in array di byte, i valori che ottengo sono diversi dai valori di array di byte originali.

Cosa posso fare per ottenere la conversione corretta? Il codice che sto usando per fare la conversione è il seguente:

// 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);

Sono bloccato in questo problema.


3
Perché in primo luogo stai cercando di convertire dati binari arbitrari in una stringa? Oltre a tutti i problemi relativi ai set di caratteri già menzionati nelle risposte, c'è anche il fatto che stai abusando di String se lo fai. Cosa c'è di sbagliato nell'uso di a byte[]per i tuoi dati binari e Stringper il tuo testo?
Joachim Sauer,

8
@Joachim - a volte hai strumenti esterni che possono fare cose come stringhe di negozi. In tal caso, si desidera poter trasformare un array di byte in una stringa (codificata in qualche modo).
James Moore,

Risposte:


377

L'array di byte deve avere una codifica. La codifica non può essere ASCII se hai valori negativi. Una volta capito, puoi convertire un set di byte in una stringa usando:

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

Ci sono un sacco di codifiche che puoi usare, guarda la classe Charset nel Sun javadocs .


4
@MauricePerry puoi spiegare perché non funzionerà UTF-8?
Asif Mushtaq

12
@UnKnown perché UTF-8 codifica alcuni caratteri come stringhe da 2 o 3 byte. Non ogni array di byte è una stringa codificata UTF-8 valida. ISO-8859-1 sarebbe una scelta migliore: qui ogni carattere è codificato come byte.
Maurice Perry,

1
Questo potrebbe funzionare, ma dovresti evitare di usare String costruttore a tutti i costi.
hfontanez

per mappare un byte su un carattere (con 8859-1) e nessuna gestione delle eccezioni (con nio.charset):String str = new String(bytes, java.nio.charset.StandardCharsets.ISO_8859_1);
iman

1
da Java 1.7, è possibile utilizzare la nuova stringa (byte, StandardCharsets.UTF_8)
ihebiheb

101

La "conversione corretta" tra byte[]e Stringè di indicare esplicitamente la codifica che si desidera utilizzare. Se si inizia con a byte[]e in realtà non contiene dati di testo, non esiste una "conversione corretta". Stringsono per il testo, byte[]è per i dati binari e l'unica cosa davvero sensata da fare è evitare la conversione tra di loro a meno che non sia assolutamente necessario.

Se è necessario utilizzare a Stringper conservare i dati binari, il modo più sicuro è utilizzare la codifica Base64 .


1
Sì, la codifica dei caratteri è qualcosa che devi sapere per convertire tra stringhe e byte.
Raedwald,

4
Base64 e tu mi hai salvato la vita
mstzn,

2
La codifica Base64 ha risolto il mio problema. UTF-8 non ha funzionato per tutti gli input
Al-Alamin,

37

Il problema alla radice è (penso) che stai inconsapevolmente usando un set di caratteri per il quale:

 bytes != encode(decode(bytes))

in alcuni casi. UTF-8 è un esempio di tale set di caratteri. In particolare, alcune sequenze di byte non sono codifiche valide in UTF-8. Se il decodificatore UTF-8 rileva una di queste sequenze, può scartare i byte offensivi o decodificarli come punto di codice Unicode per "nessun carattere del genere". Naturalmente, quando si tenta di codificare i caratteri come byte, il risultato sarà diverso.

La soluzione è:

  1. Sii esplicito sulla codifica dei caratteri che stai utilizzando; cioè usare un costruttore di stringhe eString.toByteArray metodo con un set di caratteri esplicito.
  2. Usa il set di caratteri giusto per i tuoi dati byte ... o in alternativa uno (come "Latin-1" in cui tutte le sequenze di byte sono associate a caratteri Unicode validi.
  3. Se i tuoi byte sono (realmente) dati binari e vuoi essere in grado di trasmetterli / riceverli su un canale "testuale", usa qualcosa come la codifica Base64 ... che è progettata per questo scopo .

1
Grazie per la punta dell'utilizzo della codifica "Latin-1"!
Bizzarri

31

Dobbiamo solo costruirne uno nuovo Stringcon l'array: http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/

String s = new String(bytes);

I byte della stringa risultante differiscono a seconda del set di caratteri che si utilizza. nuova stringa (byte) e nuova stringa (byte, Charset.forName ("utf-8")) e nuova stringa (byte, Charset.forName ("utf-16")) avranno tutti array di byte diversi quando si chiama String # getBytes () (a seconda del set di caratteri predefinito)


9
No. I byte della stringa risultante differiscono a seconda del set di caratteri che si utilizza. new String(bytes)e new String(bytes, Charset.forName("utf-8"))e new String(bytes, Charset.forName("utf-16"))tutti avranno array di byte diversi quando si chiama String#getBytes()(a seconda del set di caratteri predefinito)
NS du Toit,

1
Ingannevole. La chars (e quindi il testo visualizzato) del risultante Stringdifferisce quando si decodifica in modo bytesdiverso. La conversione in byte utilizzando la codifica predefinita (utilizzare String#getBytes("charset")per specificare diversamente) differirà necessariamente perché converte input diversi. Le stringhe non memorizzano da dove byte[]sono state create, chars non hanno una codifica e Stringaltrimenti non le memorizzano.
zapl,

14

L'uso new String(byOriginal)e la riconversione byte[]all'utilizzo getBytes()non garantiscono due byte[]con valori uguali. Ciò è dovuto a una chiamata a StringCoding.encode(..)cui codificherà il Stringto Charset.defaultCharset(). Durante questa codifica, il codificatore potrebbe scegliere di sostituire caratteri sconosciuti e apportare altre modifiche. Quindi, l'utilizzo String.getBytes()potrebbe non restituire un array uguale come originariamente passato al costruttore.


9

Perché il problema era: come già specificato da qualcuno: se si inizia con un byte [] e in realtà non contiene dati di testo, non esiste una "conversione corretta". Le stringhe sono per il testo, byte [] è per i dati binari e l'unica cosa davvero sensata da fare è evitare la conversione tra loro a meno che non sia assolutamente necessario.

Stavo osservando questo problema quando stavo cercando di creare byte [] da un file pdf e poi convertirlo in String e quindi prendere la String come input e riconvertirla in file.

Quindi assicurati che la tua logica di codifica e decodifica sia la stessa di me. Ho codificato esplicitamente il byte [] in Base64 e l'ho decodificato per creare nuovamente il file.

Caso d'uso: A causa di alcune limitazioni che stava cercando di inviato byte[]in request(POST)e il processo è stato il seguente:

File PDF >> Base64.encodeBase64 (byte []) >> String >> Invia in richiesta (POST) >> ricevi stringa >> Base64.decodeBase64 (byte []) >> crea binary

Prova questo e questo ha funzionato per me ..

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();
        }

6

Questo funziona bene per me:

String cd="Holding some value";

Conversione da stringa a byte []:

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

Conversione da byte [] a stringa:

cd = new sun.misc.BASE64Encoder().encode(cookie);

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;
}

1
Questo non risponde alla domanda.
james.garriss,

Non risponde alla domanda ma è stato utile +1
Lazy Ninja

5

Ho notato qualcosa che non si trova in nessuna delle risposte. È possibile trasmettere ciascuno dei byte dell'array di byte ai caratteri e inserirli in un array di caratteri. Quindi la stringa è

new String(cbuf)
dove cbuf è l'array char. Per riconvertire, scorrere la stringa che trasmette ciascuno dei caratteri in byte da inserire in un array di byte, e questo array di byte sarà lo stesso del primo.


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);
    }

}

2

javax.xml.bind.DatatypeConverter dovrebbe farlo:

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

2

Ecco alcuni metodi che convertono un array di byte in una stringa. Li ho testati, funzionano bene.

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();

}

2

Nonostante

new String(bytes, "UTF-8")

è corretto genera un valore UnsupportedEncodingExceptionche ti costringe a gestire un'eccezione controllata. È possibile utilizzare in alternativa un altro costruttore da Java 1.6 per convertire un array di byte in un String:

new String(bytes, StandardCharsets.UTF_8)

Questo non fa eccezione.

La conversione indietro dovrebbe essere eseguita anche con StandardCharsets.UTF_8:

"test".getBytes(StandardCharsets.UTF_8)

Ancora una volta eviti di dover affrontare le eccezioni verificate.


1

Sono riuscito a convertire array di byte in una stringa con questo metodo:

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();
}

1

Mentre la codifica base64 è sicura e si potrebbe sostenere "la risposta giusta", sono arrivato qui alla ricerca di un modo per convertire un array di byte Java in / da una stringa Java così com'è. Cioè, dove ogni membro dell'array di byte rimane intatto nella sua controparte String, senza spazio aggiuntivo richiesto per la codifica / trasporto.

Questa risposta che descrive le codifiche trasparenti a 8 bit è stata molto utile per me. ero solitoISO-8859-1 su terabyte di dati binari per convertire avanti e indietro con successo (binario <-> String) senza i requisiti di spazio gonfiato necessari per una codifica base64, quindi è sicuro per il mio caso d'uso - YMMV.

Questo è stato utile anche per spiegare quando / se dovresti sperimentare.


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);
}

Perché? Perché passare attraverso Base64 per convertire un byte in una stringa? Il sovraccarico.
james.garriss,

0

Qui il codice di lavoro.

            // 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);

-1

Prova a specificare un set di caratteri a 8 bit in entrambe le conversioni. ISO-8859-1 per esempio.


-1

Leggi i byte Stringdall'uso ByteArrayInputStreame avvolgilo con BufferedReaderChar Stream anziché Byte Stream che converte i dati byte in String.

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();
        }

    }
}

L'output è:

Sajal è un bravo ragazzo


-1

Puoi usare simple for loop per la conversione:

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);
}


-3

Una stringa è una raccolta di caratteri (16 bit senza segno). Quindi, se hai intenzione di convertire numeri negativi in ​​una stringa, questi verranno persi nella traduzione.


1
-1: questo non è corretto. Mentre 'byte' è un tipo con segno in Java, sono trattati come non firmati dal codice della libreria che esegue la codifica e la decodifica del set di caratteri.
Stephen C,

Un ottimo esempio del perché avere un tipo di dati a 8 bit senza segno è davvero una buona idea avere in una lingua. Evita inutili confusioni; ^)
Rospo

Fai attenzione a supporre che un carattere Java sarà di 16 bit, a causa dell'UTF-16 di Java, possono espandersi fino a 32 bit
Joe Plante,

1
@ In realtà sì, alcuni caratteri Unicode memorizzati come UTF-16 occupano due punti di codice, cioè 32 bit. Lo stesso accade in UTF-8: alcuni caratteri usano due / tre / quattro punti di codice, cioè 16/24/32 bit. In realtà, questo è esattamente ciò di cui parla UTF (ovvero UTF! = Unicode).
CAFxX

1
@Toad otterresti il ​​primo surrogato, ovvero solo la prima "metà" del personaggio. Guarda i documenti per il metodo String.charAt e la classe Character .
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);


    }

}

Passa la codifica Charset come argomento per getBytes
Shyam Sreenivasan,

1
Puoi prendere in considerazione l'idea di dare una risposta a questa risposta con una spiegazione in aggiunta al codice.
Charlie Schliesser,

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.