Da Java ByteBuffer a String


122

È questo un approccio corretto per convertire ByteBuffer in String in questo modo,

String k = "abcd";
ByteBuffer b = ByteBuffer.wrap(k.getBytes());
String v = new String(b.array());

if(k.equals(v))
    System.out.println("it worked");
else
    System.out.println("did not work");

Il motivo per cui lo chiedo è che questo sembra troppo semplice, mentre altri approcci come Java: Conversione di stringhe da e verso ByteBuffer e problemi associati sembrano più complessi.


3
Bene, l'hai provato?
tckmn

6
Sì, l'ho fatto e funziona. Ma ho visto altre implementazioni che sono più complessi, come stackoverflow.com/questions/1252468/...
vikky.rk

1
@Doorknob et. al. Manca la codifica e il suo esempio (quando la sintassi è corretta) funzionerà, ma il suo metodo non è ancora corretto.
Gus

Risposte:


83

EDIT (2018): la risposta del fratello modificata di @xinyongCheng è un approccio più semplice e dovrebbe essere la risposta accettata.

Il tuo approccio sarebbe ragionevole se sapessi che i byte sono nel set di caratteri predefinito della piattaforma. Nel tuo esempio, questo è vero perché k.getBytes()restituisce i byte nel set di caratteri predefinito della piattaforma.

Più frequentemente, ti consigliamo di specificare la codifica. Tuttavia, c'è un modo più semplice per farlo rispetto alla domanda che hai collegato. L'API String fornisce metodi che convertono tra una stringa e una matrice di byte [] in una particolare codifica. Questi metodi suggeriscono di utilizzare CharsetEncoder / CharsetDecoder "quando è richiesto un maggiore controllo sul processo di decodifica [codifica]."

Per ottenere i byte da una stringa in una particolare codifica, puoi utilizzare un metodo getBytes () di pari livello:

byte[] bytes = k.getBytes( StandardCharsets.UTF_8 );

Per inserire byte con una particolare codifica in una stringa, è possibile utilizzare un diverso costruttore di stringhe:

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

Notare che ByteBuffer.array()è un'operazione facoltativa. Se hai costruito il tuo ByteBuffer con un array, puoi usare quell'array direttamente. Altrimenti, se vuoi essere sicuro, usa ByteBuffer.get(byte[] dst, int offset, int length)per ottenere byte dal buffer in una matrice di byte.


e nella ByteBuffer.getfunzione, l'input è di nuovo un array di byte, come posso ottenerlo? non ha alcun senso ripetere k.getbytes, vero?
William Kinaan

@WilliamKinaan - Hai il byte [] a cui hai dato in pasto ByteBuffer.get(byte[] dst, int offset, int length). Puoi costruire una String da essa con il costruttore String () `String (byte [] byte, int offset, int length, Charset charset). È possibile utilizzare gli stessi valori di offset e lunghezza per entrambe le chiamate.
Andy Thomas

Non esiste un metodo k.getBytes () in java.nio.ByteBuffer (potrebbe non essere nella versione che sto utilizzando). Quindi ho usato il metodo k.array () che restituirà byte [].
Madura Pradeep

@MaduraPradeep - Nel codice di esempio nella domanda e in questa risposta, kè una stringa, non un ByteBuffer.
Andy Thomas,

Tieni presente che UTF-8 potrebbe non essere il set di caratteri ottimale per convertire i byte in stringhe e viceversa. Per una mappatura 1-a-1 di byte di caratteri migliore utilizzo ISO-8859-1, vedere stackoverflow.com/questions/9098022/...
asmaier

103

C'è un approccio più semplice per decodificare a ByteBufferin a Stringsenza problemi, menzionato da Andy Thomas.

String s = StandardCharsets.UTF_8.decode(byteBuffer).toString();

2
Tieni presente che UTF-8 potrebbe non essere il set di caratteri ottimale per convertire i byte in stringhe e viceversa. Per una mappatura 1 a 1 di byte in caratteri, utilizzare meglio ISO-8859-1, vedere stackoverflow.com/questions/9098022/… .
asmaier

Inoltre, se non hai davvero bisogno di una stringa, il CharBuffer decode()ritorno è un CharSequence(mi piace String), quindi puoi evitare una copia extra e usarla direttamente.
David Ehrmann dal

15

Prova questo:

new String(bytebuffer.array(), "ASCII");

NB. non è possibile convertire correttamente un array di byte in una stringa senza conoscerne la codifica.

Spero che aiuti


10
UTF-8 è probabilmente un'ipotesi predefinita migliore di ASCII?
Gus

3
Nessuno dei due dovrebbe essere specificato, dato l'uso da parte dell'OP di k.getBytes (), che utilizza il set di caratteri predefinito della piattaforma.
Andy Thomas,

7
Non tutti i buffer sono supportati da un array, quindi .array()potrebbe generare un'eccezione.
Dzmitry Lazerka

Non tutti i bytebuffer supportano il .array()metodo.
ScalaWilliam

3
! attento Se si utilizza array(), è necessario utilizzare anche arrayOffset()per iniziare dalla posizione corretta nell'array! Questa è una trappola sottile, perché di solito arrayOffset () è 0; ma in quei rari casi in cui non lo è, se non lo prendi in considerazione, otterrai bug difficili da trovare.
oliver

13

Volevo solo sottolineare che non è sicuro presumere che ByteBuffer.array () funzionerà sempre.

byte[] bytes;
if(buffer.hasArray()) {
    bytes = buffer.array();
} else {
    bytes = new byte[buffer.remaining()];
    buffer.get(bytes);
}
String v = new String(bytes, charset);

Di solito buffer.hasArray () sarà sempre vero o falso a seconda del tuo caso d'uso. In pratica, a meno che tu non voglia davvero che funzioni in qualsiasi circostanza, è sicuro ottimizzare il ramo che non ti serve. Ma il resto delle risposte potrebbe non funzionare con un ByteBuffer creato tramite ByteBuffer.allocateDirect ().


Se il buffer viene creato tramite ByteBuffer.wrap(bytes, offset, size)factory .array()restituirà l'intero bytesarray. Usa meglio la forma suggerita da xinyong Cheng
Lev Kuznetsov

Il .decode () su Charset è una soluzione migliore, d'accordo. Penso che il contesto della mia risposta sia un'informazione utile, ma molto meno ora.
Fuwjax

2
! attento Se si utilizza array(), è necessario utilizzare anche arrayOffset()per iniziare dalla posizione corretta nell'array! Questa è una trappola sottile, perché di solito arrayOffset () è 0; ma in quei rari casi in cui non lo è, se non lo prendi in considerazione, otterrai bug difficili da trovare.
oliver

8

Le risposte che si riferiscono alla semplice chiamata array()non sono del tutto corrette: quando il buffer è stato parzialmente consumato, o si riferisce a una parte di un array (puoi ByteBuffer.wrapun array a un dato offset, non necessariamente dall'inizio), dobbiamo tenerne conto quello nei nostri calcoli. Questa è la soluzione generale che funziona per i buffer in tutti i casi (non copre la codifica):

if (myByteBuffer.hasArray()) {
    return new String(myByteBuffer.array(),
        myByteBuffer.arrayOffset() + myByteBuffer.position(),
        myByteBuffer.remaining());
} else {
    final byte[] b = new byte[myByteBuffer.remaining()];
    myByteBuffer.duplicate().get(b);
    return new String(b);
}

Per le preoccupazioni relative alla codifica, vedere la risposta di Andy Thomas.


2

la radice di questa domanda è come decodificare i byte in stringa?

questo può essere fatto con il set di caratteri JAVA NIO:

public final CharBuffer decode(ByteBuffer bb)

FileChannel channel = FileChannel.open(
  Paths.get("files/text-latin1.txt", StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);

CharSet latin1 = StandardCharsets.ISO_8859_1;
CharBuffer latin1Buffer = latin1.decode(buffer);

String result = new String(latin1Buffer.array());
  • Per prima cosa creiamo un canale e lo leggiamo in un buffer
  • Quindi il metodo decode decodifica un buffer Latin1 in un buffer char
  • Possiamo quindi mettere il risultato, ad esempio, in una stringa

Il tuo codice non viene decodificato da latin1 a utf8. Sebbene il tuo codice sia corretto, chiamare CharBuffer utf8Buffer è in qualche modo fuorviante perché non ha codifica.
Björn Lindqvist

1

Si noti (a parte il problema della codifica) che parte del codice più complicato collegato si prende la briga di ottenere la parte "attiva" del ByteBuffer in questione (ad esempio utilizzando posizione e limite), piuttosto che semplicemente codificare tutti i byte nell'intero array di supporto (come fanno molti degli esempi in queste risposte).


1

Converti una stringa in ByteBuffer, quindi da ByteBuffer di nuovo in String usando Java:

import java.nio.charset.Charset;
import java.nio.*;

String babel = "obufscate thdé alphebat and yolo!!";
System.out.println(babel);
//Convert string to ByteBuffer:
ByteBuffer babb = Charset.forName("UTF-8").encode(babel);
try{
    //Convert ByteBuffer to String
    System.out.println(new String(babb.array(), "UTF-8"));
}
catch(Exception e){
    e.printStackTrace();
}

Che stampa prima la stringa nuda stampata, quindi il ByteBuffer convertito in array ():

obufscate thdé alphebat and yolo!!
obufscate thdé alphebat and yolo!!

Anche questo è stato utile per me, ridurre la stringa a byte primitivi può aiutare a controllare cosa sta succedendo:

String text = "こんにちは";
//convert utf8 text to a byte array
byte[] array = text.getBytes("UTF-8");
//convert the byte array back to a string as UTF-8
String s = new String(array, Charset.forName("UTF-8"));
System.out.println(s);
//forcing strings encoded as UTF-8 as an incorrect encoding like
//say ISO-8859-1 causes strange and undefined behavior
String sISO = new String(array, Charset.forName("ISO-8859-1"));
System.out.println(sISO);

Stampa la tua stringa interpretata come UTF-8 e poi di nuovo come ISO-8859-1:

こんにちは
ããã«ã¡ã¯

0
private String convertFrom(String lines, String from, String to) {
    ByteBuffer bb = ByteBuffer.wrap(lines.getBytes());
    CharBuffer cb = Charset.forName(to).decode(bb);
    return new String(Charset.forName(from).encode(cb).array());
};
public Doit(){
    String concatenatedLines = convertFrom(concatenatedLines, "CP1252", "UTF-8");
};
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.