Conversione di array di byte in String (Java)


85

Sto scrivendo un'applicazione web in Google app Engine. Consente alle persone di modificare sostanzialmente il codice html che viene archiviato come .htmlfile nel blobstore.

Sto usando fetchData per restituire uno byte[]di tutti i caratteri nel file. Sto cercando di stampare su un html in modo che l'utente possa modificare il codice html. Tutto funziona alla grande!

Ecco il mio unico problema ora:

L'array di byte presenta alcuni problemi durante la riconversione in una stringa. Citazioni intelligenti e un paio di personaggi stanno uscendo con un aspetto funky. (? o simboli giapponesi, ecc.) In particolare, vedo diversi byte che hanno valori negativi che causano il problema.

Le virgolette intelligenti stanno tornando come -108e -109nell'array di byte. Perché questo e come posso decodificare i byte negativi per mostrare la codifica dei caratteri corretta?



Ciao, so che è un post davvero vecchio ma sto affrontando problemi simili. Sto creando un proxy man-in-the-middle per ssl. Il problema che sto affrontando è lo stesso del tuo. Ascolto il socket e inserisco i dati InputStreame poi in byte[]. Ora, quando provo a convertire il byte[]in String (ho bisogno di usare il corpo della risposta per gli attacchi), ottengo caratteri davvero divertenti pieni di virgolette intelligenti e punti interrogativi e cosa no. Credo che il tuo problema è uguale al mio come ci sia a che fare con htmlin byte[]. Puoi per favore un consiglio?
Parul S

A proposito, sono andato al punto di trovare la codifica del mio sistema utilizzando Sytem.properties e ho scoperto che era "Cp1252". Ora, ho usato String str=new String(buffer, "Cp1252");ma nessun aiuto.
Parul S

Risposte:


141

L'array di byte contiene caratteri in una codifica speciale (che dovresti conoscere). Il modo per convertirlo in una stringa è:

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

A proposito: i byte grezzi possono apparire come decimali negativi solo perché il tipo di dati java byteè firmato, copre l'intervallo da -128 a 127.


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

Il valore (-109) è un carattere di controllo non stampabile in UNICODE. Quindi UTF-8 non è la codifica corretta per quel flusso di caratteri.

0x93in "Windows-1252" è la "citazione intelligente" che stai cercando, quindi il nome Java di quella codifica è "Cp1252". La riga successiva fornisce un codice di prova:

System.out.println(new String(new byte[]{-109}, "Cp1252")); 

5
Ho provato a usare UTF-8 e ancora è uscito come?. Come mai non trova una mappatura per quei valori negativi?
Josh

0x93 è un byte di continuazione valido in UTF-8, tuttavia - la presenza di quel byte esclude che sia UTF-8 solo se non viene dopo un byte con i primi due bit impostati.
Nick Johnson

1
@ Josh Andreas spiega perché - perché il bytetipo di dati di Java è firmato. I valori "negativi" sono solo byte con il set di byte più significativo. Spiega anche quale sia il set di caratteri più probabile che dovresti usare: Windows-1252. Tuttavia, dovresti sapere quale set di caratteri usare dal contesto o dalla convenzione, senza dover indovinare.
Nick Johnson

25

Java 7 e versioni successive

Puoi anche passare la codifica desiderata al Stringcostruttore come Charsetcostante da StandardCharsets . Questo può essere più sicuro che passare la codifica come a String, come suggerito nelle altre risposte.

Ad esempio, per la codifica UTF-8

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

1
Questa è una
replica

2
@ james.garriss Non credo che lo sia, in quanto sto solo citando un nuovo costruttore introdotto in java 7 che consente di passare la codifica come costante, che a mio parere è più bello e più sicuro dell'API precedente menzionato nelle risposte precedenti in cui la codifica è stata passata come una stringa, se non del tutto.
davnicwil


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

Produzione

65
65
A

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
}

3
Questo codice perderà una risorsa se readgenera un'eccezione.
Raedwald

4

suggerisco Arrays.toString(byte_array);

Dipende dal tuo scopo. Ad esempio, volevo salvare un array di byte esattamente come il formato che puoi vedere al momento del debug che è qualcosa del genere: [1, 2, 3]se vuoi salvare esattamente lo stesso valore senza convertire i byte in formato carattere, Arrays.toString (byte_array)fa questo. Ma se vuoi salvare caratteri invece di byte, dovresti usare String s = new String(byte_array). In questo caso, sè uguale all'equivalente di [1, 2, 3]in formato di carattere.


Puoi fornire maggiori informazioni sul motivo per cui lo suggerisci? (Risolverà il problema? Puoi dire perché lo risolve?) Grazie!
Dean J

Dipende dal tuo scopo. Ad esempio, volevo salvare un array di byte esattamente come il formato che puoi vedere al momento del debug che è qualcosa del genere: [1, 2, 3] Se vuoi salvare esattamente lo stesso valore senza convertire i byte in formato carattere, Arrays.toString (byte_array) fa questo. Ma se vuoi salvare i caratteri invece dei byte, dovresti usare String s = new String (byte_array). In questo caso, s è uguale all'equivalente di [1, 2, 3] nel formato del carattere.
Interrogante

@sas, dovresti aggiungere queste informazioni alla tua risposta stessa (modificandola) piuttosto che come commento. Generalmente su SO dovresti sempre tenere presente che i commenti possono essere cancellati in qualsiasi momento - le informazioni veramente importanti dovrebbero essere nella risposta stessa.
Jeen Broekstra

3

La risposta precedente di Andreas_D è buona. Aggiungerò solo che ovunque si visualizzi l'output ci saranno un font e una codifica dei caratteri e potrebbe non supportare alcuni caratteri.

Per capire se il problema è Java o il tuo display, procedi come segue:

    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 avrà mappato tutti i caratteri che non può comprendere in 0xfffd il carattere ufficiale per i caratteri sconosciuti. Se vedi un "?" nell'output, ma non è mappato a 0xfffd, il problema è il carattere o la codifica del display, non Java.

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.