Java ByteBuffer ke String

122

Apakah ini pendekatan yang benar untuk mengubah ByteBuffer menjadi String dengan cara ini,

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

Alasan saya bertanya adalah apakah ini terlihat terlalu sederhana, sedangkan pendekatan lain seperti Java: Mengubah String ke dan dari ByteBuffer dan masalah terkait terlihat lebih kompleks.

vikky.rk
sumber
3
Nah, sudahkah Anda mencobanya?
tckmn
6
Ya saya lakukan dan berhasil. Tetapi saya telah melihat implementasi lain yang lebih kompleks, seperti stackoverflow.com/questions/1252468/…
vikky.rk
1
@Doorkob et. Al. Dia kehilangan pengkodean dan contohnya (saat sintaks dikoreksi) akan berfungsi, tetapi metodenya masih belum benar.
Gus

Jawaban:

83

EDIT (2018): Jawaban saudara yang diedit oleh @xinyongCheng adalah pendekatan yang lebih sederhana, dan harus menjadi jawaban yang diterima.

Pendekatan Anda akan masuk akal jika Anda mengetahui bahwa byte-byte tersebut ada di charset default platform. Dalam contoh Anda, ini benar karena k.getBytes()mengembalikan byte dalam rangkaian karakter default platform.

Lebih sering, Anda ingin menentukan pengkodean. Namun, ada cara yang lebih sederhana untuk melakukannya selain pertanyaan yang Anda tautkan. String API menyediakan metode yang mengubah antara String dan array [] byte dalam pengkodean tertentu. Metode ini menyarankan penggunaan CharsetEncoder / CharsetDecoder "ketika kontrol lebih besar atas proses decoding [encoding] diperlukan."

Untuk mendapatkan byte dari String dalam encoding tertentu, Anda bisa menggunakan metode getBytes () saudara:

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

Untuk meletakkan byte dengan pengkodean tertentu ke dalam String, Anda dapat menggunakan konstruktor String yang berbeda:

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

Perhatikan bahwa ByteBuffer.array()ini adalah operasi opsional. Jika Anda telah membangun ByteBuffer Anda dengan sebuah array, Anda dapat menggunakan array itu secara langsung. Jika tidak, jika Anda ingin aman, gunakan ByteBuffer.get(byte[] dst, int offset, int length)untuk mendapatkan byte dari buffer ke dalam array byte.

Andy Thomas
sumber
dan dalam ByteBuffer.getfungsinya, inputnya lagi berupa array byte, bagaimana saya bisa mendapatkannya? tidak masuk akal untuk mengatakan lagi k.getbytes, bukan?
William Kinaan
@WilliamKinaan - Anda memiliki byte [] yang Anda kirim ByteBuffer.get(byte[] dst, int offset, int length). Anda bisa membuat String darinya dengan konstruktor String () `String (byte [] bytes, int offset, int length, Charset charset). Anda dapat menggunakan nilai offset dan panjang yang sama untuk kedua panggilan.
Andy Thomas
Tidak ada metode k.getBytes () di java.nio.ByteBuffer (mungkin tidak dalam versi yang saya gunakan). Jadi saya menggunakan metode k.array () yang akan mengembalikan byte [].
Madura Pradeep
@MaduraPradeep - Dalam kode contoh di pertanyaan dan jawaban ini, kadalah String, bukan ByteBuffer.
Andy Thomas
Ketahuilah bahwa UTF-8 mungkin bukan rangkaian karakter yang optimal untuk mengonversi byte menjadi string dan sebaliknya. Untuk pemetaan byte ke karakter 1-ke-1 dengan lebih baik, gunakan ISO-8859-1, lihat stackoverflow.com/questions/9098022/…
asmaier
103

Ada pendekatan yang lebih sederhana untuk memecahkan kode a ByteBuffermenjadi Stringtanpa masalah, yang disebutkan oleh Andy Thomas.

String s = StandardCharsets.UTF_8.decode(byteBuffer).toString();
xinyong Cheng
sumber
2
Ketahuilah bahwa UTF-8 mungkin bukan rangkaian karakter yang optimal untuk mengonversi byte menjadi string dan sebaliknya. Untuk pemetaan byte ke karakter 1-ke-1 dengan lebih baik, gunakan ISO-8859-1, lihat stackoverflow.com/questions/9098022/… .
asmaier
Selain itu, jika Anda tidak benar - benar membutuhkan string, CharBuffer decode()kembaliannya adalah CharSequence(like String), sehingga Anda dapat menghindari salinan tambahan dan menggunakannya secara langsung.
David Ehrmann
15

Coba ini:

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

NB. Anda tidak dapat mengubah array byte dengan benar menjadi String tanpa mengetahui pengkodeannya.

saya harap ini membantu

Dan Bray
sumber
10
UTF-8 mungkin merupakan tebakan default yang lebih baik daripada ASCII?
Gus
3
Tidak ada yang harus ditentukan, mengingat penggunaan OP atas k.getBytes (), yang menggunakan charset default platform.
Andy Thomas
7
Tidak semua buffer didukung oleh sebuah array, jadi .array()mungkin ada pengecualian.
Dzmitry Lazerka
Tidak semua bytebuffers mendukung .array()metode ini.
ScalaWilliam
3
Cermat! Jika Anda menggunakan array(), Anda juga harus menggunakan arrayOffset()untuk memulai dari posisi yang benar dalam larik! Ini adalah kesalahan kecil, karena biasanya arrayOffset () adalah 0; tetapi dalam kasus yang jarang terjadi di mana tidak, Anda akan mendapatkan bug yang sulit ditemukan jika Anda tidak memperhitungkannya.
oliver
13

Hanya ingin menunjukkan, tidak aman mengasumsikan ByteBuffer.array () akan selalu berfungsi.

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

Biasanya buffer.hasArray () akan selalu benar atau salah tergantung pada kasus penggunaan Anda. Dalam praktiknya, kecuali jika Anda benar-benar ingin berfungsi dalam keadaan apa pun, aman untuk mengoptimalkan cabang yang tidak Anda perlukan. Tetapi jawaban lainnya mungkin tidak berfungsi dengan ByteBuffer yang dibuat melalui ByteBuffer.allocateDirect ().

Fuwjax
sumber
Jika buffer dibuat melalui ByteBuffer.wrap(bytes, offset, size)pabrik .array()akan mengembalikan seluruh bytesarray. Lebih baik gunakan bentuk xinyong Cheng yang disarankan
Lev Kuznetsov
.Decode () di Charset adalah solusi yang lebih baik, setuju. Saya merasa konteks jawaban saya adalah informasi yang berguna, tetapi sekarang tidak begitu.
Fuwjax
2
Cermat! Jika Anda menggunakan array(), Anda juga harus menggunakan arrayOffset()untuk memulai dari posisi yang benar dalam larik! Ini adalah kesalahan kecil, karena biasanya arrayOffset () adalah 0; tetapi dalam kasus yang jarang terjadi di mana tidak, Anda akan mendapatkan bug yang sulit ditemukan jika Anda tidak memperhitungkannya.
oliver
8

Jawaban yang mengacu pada panggilan array()tidak sepenuhnya benar: ketika buffer telah dikonsumsi sebagian, atau mengacu pada bagian dari array (Anda dapat ByteBuffer.wrapmembuat array pada offset tertentu, tidak harus dari awal), kita harus memperhitungkan itu dalam perhitungan kami. Ini adalah solusi umum yang berfungsi untuk buffer di semua kasus (tidak mencakup encoding):

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

Untuk masalah yang terkait dengan pengkodean, lihat jawaban Andy Thomas.

Alex Yarmula
sumber
2

akar dari pertanyaan ini adalah bagaimana cara memecahkan kode byte menjadi string?

ini dapat dilakukan dengan JAVA NIO CharSet:

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());
  • Pertama kita membuat saluran dan membacanya di buffer
  • Kemudian metode decode menerjemahkan buffer Latin1 ke buffer karakter
  • Kami kemudian dapat meletakkan hasilnya, misalnya, dalam sebuah String
宏杰 李
sumber
Kode Anda tidak didekode dari latin1 ke utf8. Meskipun kode Anda benar, memanggil CharBuffer utf8Buffer agak menyesatkan karena tidak memiliki pengkodean.
Björn Lindqvist
1

Perhatikan (selain dari masalah encoding) bahwa beberapa kode yang lebih rumit yang ditautkan mengalami kesulitan untuk mendapatkan bagian "aktif" dari ByteBuffer yang dimaksud (misalnya dengan menggunakan posisi dan limit), daripada hanya mengenkode semua byte di seluruh larik pendukung (seperti yang dilakukan banyak contoh dalam jawaban ini).

Jas
sumber
1

Ubah String menjadi ByteBuffer, lalu dari ByteBuffer kembali ke String menggunakan 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();
}

Yang mencetak string kosong yang dicetak terlebih dahulu, dan kemudian ByteBuffer dicor ke array ():

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

Ini juga berguna bagi saya, mengurangi string menjadi byte primitif dapat membantu memeriksa apa yang terjadi:

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

Mencetak string Anda yang ditafsirkan sebagai UTF-8, dan kemudian lagi sebagai ISO-8859-1:

こんにちは
ããã«ã¡ã¯
Eric Leschinski
sumber
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
sumber
0

Berikut adalah fungsi sederhana untuk mengubah buffer byte menjadi string:

public String byteBufferToString(ByteBuffer bufferData) {
    byte[] buffer = new byte[bufferData.readableByteCount()];
    // read bufferData and insert into buffer 
    data.read(buffer);
    // CharsetUtil supports UTF_16, ASCII, and many more
    String text = new String(buffer, CharsetUtil.UTF_8);
    System.out.println("Text: "+text);
    return text;
}
Jitendra Asawa
sumber