Java ByteBuffer to String

121

Ist dies ein korrekter Ansatz, um ByteBuffer auf diese Weise in String zu konvertieren?

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

Der Grund, den ich frage, ist, dass dies zu einfach aussieht, während andere Ansätze wie Java: Das Konvertieren von Zeichenfolgen in und aus ByteBuffer und die damit verbundenen Probleme komplexer aussehen.

vikky.rk
quelle
3
Hast du es versucht?
Tckmn
6
Ja, ich habe es getan und es funktioniert. Aber ich habe andere Implementierungen gesehen, die komplexer sind, wie stackoverflow.com/questions/1252468/…
vikky.rk
1
@ Doorknob et. al. Ihm fehlt die Codierung und sein Beispiel (wenn die Syntax korrigiert ist) wird funktionieren, aber seine Methode ist immer noch nicht richtig.
Gus

Antworten:

83

EDIT (2018): Die bearbeitete Geschwisterantwort von @xinyongCheng ist ein einfacherer Ansatz und sollte die akzeptierte Antwort sein.

Ihr Ansatz wäre vernünftig, wenn Sie wüssten, dass die Bytes im Standardzeichensatz der Plattform enthalten sind. In Ihrem Beispiel ist dies wahr, weilk.getBytes() die Bytes im Standardzeichensatz der Plattform zurückgegeben werden.

Häufiger möchten Sie die Codierung angeben. Es gibt jedoch einen einfacheren Weg, dies zu tun als die von Ihnen verknüpfte Frage. Die String-API bietet Methoden, die in einer bestimmten Codierung zwischen einem String- und einem Byte [] -Array konvertieren. Diese Methoden empfehlen die Verwendung von CharsetEncoder / CharsetDecoder "wenn mehr Kontrolle über den Decodierungsprozess erforderlich ist".

Um die Bytes aus einem String in einer bestimmten Codierung abzurufen, können Sie eine Geschwister-Methode getBytes () verwenden:

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

Um Bytes mit einer bestimmten Codierung in einen String einzufügen, können Sie einen anderen String-Konstruktor verwenden:

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

Beachten Sie, dass dies ByteBuffer.array()eine optionale Operation ist. Wenn Sie Ihren ByteBuffer mit einem Array erstellt haben, können Sie dieses Array direkt verwenden. Wenn Sie andernfalls sicher sein möchten, verwenden Sie ByteBuffer.get(byte[] dst, int offset, int length), um Bytes aus dem Puffer in ein Byte-Array zu übertragen.

Andy Thomas
quelle
und in der ByteBuffer.getFunktion ist die Eingabe wieder ein Array von Bytes, wie kann ich es bekommen? es macht keinen Sinn, noch einmal k.getbytes zu sagen, oder?
William Kinaan
@WilliamKinaan - Sie haben das Byte [], dem Sie zugeführt haben ByteBuffer.get(byte[] dst, int offset, int length). Sie können daraus einen String mit dem String () -Konstruktor `String (Byte [] Bytes, Int-Offset, Int-Länge, Zeichensatz-Zeichensatz) erstellen. Sie können für beide Aufrufe dieselben Offset- und Längenwerte verwenden.
Andy Thomas
Es gibt keine k.getBytes () -Methode in java.nio.ByteBuffer (möglicherweise nicht in der von mir verwendeten Version). Also habe ich die Methode k.array () verwendet, die Byte [] zurückgibt.
Madura Pradeep
@MaduraPradeep - Im Beispielcode in der Frage und dieser Antwort khandelt es sich um einen String und nicht um einen ByteBuffer.
Andy Thomas
Beachten Sie, dass UTF-8 möglicherweise nicht der optimale Zeichensatz für die Konvertierung von Bytes in Zeichenfolgen ist und umgekehrt. Eine 1: 1-Zuordnung von Bytes zu Zeichen finden Sie unter ISO-8859-1 unter stackoverflow.com/questions/9098022/…
asmaier
102

Es gibt einen einfacheren Ansatz, um a ohne Probleme ByteBufferin ein zu dekodieren String, wie von Andy Thomas erwähnt.

String s = StandardCharsets.UTF_8.decode(byteBuffer).toString();
Xinyong Cheng
quelle
2
Beachten Sie, dass UTF-8 möglicherweise nicht der optimale Zeichensatz für die Konvertierung von Bytes in Zeichenfolgen ist und umgekehrt. Eine 1: 1-Zuordnung von Bytes zu Zeichen finden Sie unter ISO-8859-1 unter stackoverflow.com/questions/9098022/… .
Asmaier
Auch der Sie nicht wirklich eine Zeichenfolge benötigen, die CharBuffer decode()ist kehrt ein CharSequence(wie String), so dass Sie eine zusätzliche Kopie vermeiden können und es direkt verwenden.
David Ehrmann
15

Versuche dies:

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

NB. Sie können ein Byte-Array nicht korrekt in einen String konvertieren, ohne dessen Codierung zu kennen.

ich hoffe das hilft

Dan Bray
quelle
10
UTF-8 ist wahrscheinlich eine bessere Standardschätzung als ASCII?
Gus
3
Beides sollte nicht angegeben werden, da das OP k.getBytes () verwendet, das den Standardzeichensatz der Plattform verwendet.
Andy Thomas
7
Nicht alle Puffer werden von einem Array unterstützt, daher .array()kann eine Ausnahme ausgelöst werden.
Dzmitry Lazerka
Nicht alle Bytebuffer unterstützen die .array()Methode.
ScalaWilliam
3
Vorsichtig! Wenn Sie verwenden array(), müssen Sie auch verwenden arrayOffset(), um an der richtigen Position im Array zu beginnen! Dies ist eine subtile Gefahr, da arrayOffset () normalerweise 0 ist. Aber in den seltenen Fällen, in denen dies nicht der Fall ist, werden Sie schwer zu findende Fehler bekommen, wenn Sie dies nicht berücksichtigen.
Oliver
13

Ich wollte nur darauf hinweisen, dass es nicht sicher ist anzunehmen, dass ByteBuffer.array () immer funktioniert.

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

Normalerweise ist buffer.hasArray () je nach Anwendungsfall immer wahr oder falsch. In der Praxis ist es sicher, den nicht benötigten Zweig zu optimieren, es sei denn, Sie möchten wirklich, dass er unter keinen Umständen funktioniert. Die restlichen Antworten funktionieren jedoch möglicherweise nicht mit einem ByteBuffer, der über ByteBuffer.allocateDirect () erstellt wurde.

Fuwjax
quelle
Wenn der Puffer über ByteBuffer.wrap(bytes, offset, size)Factory erstellt .array()wird, wird das gesamte bytesArray zurückgegeben. Verwenden Sie besser die von Xinyong Cheng vorgeschlagene Form
Lev Kuznetsov
Die .decode () auf Charset ist eine bessere Lösung, vereinbart. Ich bin der Meinung, dass der Kontext meiner Antwort nützliche Informationen sind, aber jetzt noch viel weniger.
Fuwjax
2
Vorsichtig! Wenn Sie verwenden array(), müssen Sie auch verwenden arrayOffset(), um an der richtigen Position im Array zu beginnen! Dies ist eine subtile Gefahr, da arrayOffset () normalerweise 0 ist. Aber in den seltenen Fällen, in denen dies nicht der Fall ist, werden Sie schwer zu findende Fehler bekommen, wenn Sie dies nicht berücksichtigen.
Oliver
8

Die Antworten, die sich auf das einfache Aufrufen beziehen, array()sind nicht ganz richtig: Wenn der Puffer teilweise verbraucht wurde oder sich auf einen Teil eines Arrays bezieht (Sie können ByteBuffer.wrapein Array mit einem bestimmten Offset erstellen, nicht unbedingt von Anfang an), müssen wir dies berücksichtigen das in unseren Berechnungen. Dies ist die allgemeine Lösung, die in allen Fällen für Puffer funktioniert (gilt nicht für die Codierung):

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

Zu den Bedenken im Zusammenhang mit der Codierung siehe die Antwort von Andy Thomas.

Alex Yarmula
quelle
1

Beachten Sie (abgesehen vom Codierungsproblem), dass ein Teil des komplizierteren verknüpften Codes dazu führt, dass der "aktive" Teil des betreffenden ByteBuffers abgerufen wird (z. B. durch Verwendung von Position und Limit), anstatt einfach alle Bytes zu codieren im gesamten Hintergrundarray (wie viele der Beispiele in diesen Antworten).

Jas
quelle
1

Konvertieren Sie einen String in ByteBuffer und dann mit Java von ByteBuffer zurück in String:

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

Womit zuerst die gedruckte bloße Zeichenfolge und dann der in array () umgesetzte ByteBuffer gedruckt werden:

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

Auch dies war für mich hilfreich. Wenn Sie die Zeichenfolge auf primitive Bytes reduzieren, können Sie überprüfen, was gerade passiert:

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

Druckt Ihre Zeichenfolge als UTF-8 und dann erneut als ISO-8859-1:

こんにちは
ããã«ã¡ã¯
Eric Leschinski
quelle
1

Die Wurzel dieser Frage ist wie man Bytes in einen String dekodiert.

Dies kann mit dem JAVA NIO CharSet erfolgen:

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());
  • Zuerst erstellen wir einen Kanal und lesen ihn in einem Puffer
  • Dann decodiert die Decodierungsmethode einen Latin1-Puffer in einen Zeichenpuffer
  • Wir können das Ergebnis dann zum Beispiel in einen String einfügen
宏杰 李
quelle
Ihr Code dekodiert nicht von latin1 nach utf8. Während Ihr Code korrekt ist, ist das Aufrufen des CharBuffer utf8Buffer etwas irreführend, da er keine Codierung hat.
Björn Lindqvist
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");
};
Koenraad Appelo
quelle