簡體   English   中英

Java ByteBuffer 轉字符串

[英]Java ByteBuffer to String

這是以這種方式將 ByteBuffer 轉換為 String 的正確方法嗎,

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

我問的原因是這看起來太簡單了,而其他方法如Java:將字符串轉換為 ByteBuffer 和相關問題看起來更復雜。

Andy Thomas 提到有一種更簡單的方法可以將ByteBuffer解碼為String而不會出現任何問題。

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

編輯(2018): @xinyongCheng 編輯的兄弟答案是一種更簡單的方法,應該是公認的答案。

如果您知道字節在平台的默認字符集中,您的方法將是合理的。 在您的示例中,這是正確的,因為k.getBytes()返回平台默認字符k.getBytes()的字節。

更常見的是,您需要指定編碼。 但是,有一種比您鏈接的問題更簡單的方法。 String API 提供了以特定編碼在 String 和 byte[] 數組之間進行轉換的方法。 這些方法建議使用 CharsetEncoder/CharsetDecoder, “當需要對解碼 [編碼] 過程進行更多控制時”。

要從特定編碼的字符串中獲取字節,您可以使用同級 getBytes() 方法:

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

要將具有特定編碼的字節放入 String,您可以使用不同的 String 構造函數:

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

請注意, ByteBuffer.array()是一個可選操作。 如果您使用數組構建了 ByteBuffer,則可以直接使用該數組。 否則,如果您想安全,請使用ByteBuffer.get(byte[] dst, int offset, int length)從緩沖區獲取字節到字節數組中。

試試這個:

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

注意。 在不知道其編碼的情況下,您無法正確地將字節數組轉換為字符串。

我希望這有幫助

只是想指出,假設 ByteBuffer.array() 總是有效是不安全的。

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

通常 buffer.hasArray() 將始終為 true 或 false,具體取決於您的用例。 在實踐中,除非你真的希望它在任何情況下都能工作,否則優化掉你不需要的分支是安全的。 但是其余的答案可能不適用於通過 ByteBuffer.allocateDirect() 創建的 ByteBuffer。

簡單地調用array()的答案並不完全正確:當緩沖區被部分消耗時,或者指的是數組的一部分(您可以ByteBuffer.wrap給定偏移量的數組,不一定從頭開始) ,我們必須在計算中考慮到這一點。 這是適用於所有情況下的緩沖區的通用解決方案(不包括編碼):

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

有關與編碼相關的問題,請參閱 Andy Thomas 的回答。

這個問題的根源是如何將字節解碼為字符串?

這可以通過 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());
  • 首先我們創建一個通道並在緩沖區中讀取它
  • 然后decode方法將一個Latin1緩沖區解碼為一個char緩沖區
  • 然后我們可以把結果,例如,在一個字符串中

將 String 轉換為 ByteBuffer,然后使用 Java 將 ByteBuffer 轉換回 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();
}

它首先打印打印的裸字符串,然后將 ByteBuffer 轉換為 array():

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

這對我也很有幫助,將字符串減少到原始字節可以幫助檢查發生了什么:

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

打印解釋為 UTF-8 的字符串,然后再次打印為 ISO-8859-1:

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

請注意(除了編碼問題),一些更復雜的鏈接代碼在獲取有問題的 ByteBuffer 的“活動”部分時遇到了麻煩(例如通過使用位置和限制),而不是簡單地對所有字節進行編碼在整個支持數組中(就像這些答案中的許多示例一樣)。

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

這是一個將字節緩沖區轉換為字符串的簡單函數:

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

這是在java.nio.ByteBuffer實例上對我java.nio.ByteBuffer的唯一方法:

String fileContent = new String(bb.array(), StandardCharsets.UTF_8);

相關代碼片段如下:

import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;


Path path = Paths.get("/home/binita/testbb");
FileChannel fileChannel = FileChannel.open(path, 
                 EnumSet.of(StandardOpenOption.READ
                    )
                 );  
            
ByteBuffer bb = ByteBuffer.allocate(1024);
int bytesRead = fileChannel.read(bb);
if(bytesRead > 0) {
 String fileContent = new String(bb.array(), StandardCharsets.UTF_8);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM