Java ByteBuffer 到字符串
Posted
技术标签:
【中文标题】Java ByteBuffer 到字符串【英文标题】:Java ByteBuffer to String 【发布时间】:2013-06-25 15:32:32 【问题描述】:这样把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: Converting String to and from ByteBuffer and associated problems 这样的其他方法看起来更复杂。
【问题讨论】:
嗯,你试过了吗? 是的,我做到了,它有效。但我见过其他更复杂的实现,比如***.com/questions/1252468/… @Doorknob 等。人。他缺少编码,他的例子(当语法被纠正时)会起作用,但他的方法仍然不正确。 【参考方案1】:Andy Thomas 提到,有一种更简单的方法可以毫无问题地将 ByteBuffer
解码为 String
。
String s = StandardCharsets.UTF_8.decode(byteBuffer).toString();
【讨论】:
请注意,UTF-8 可能不是将字节转换为字符串的最佳字符集,反之亦然。对于字节到字符的一对一映射,最好使用 ISO-8859-1,请参阅***.com/questions/9098022/…。 另外,你们中的真的不需要字符串,CharBuffer
decode()
返回的是CharSequence
(如String
),所以你可以避免额外的副本并直接使用它。
@DavidEhrmann CharBuffer 没有解码方法 - 你在这里指的是什么?
@TomAnderson Charset
有一个 decode()
方法。
@DavidEhrmann 啊!我完全误解了你的评论,对不起!【参考方案2】:
EDIT (2018):编辑的兄弟answer by @xinyongCheng is a simpler approach, and should be the accepted answer。
如果您知道字节在平台的默认字符集中,您的方法将是合理的。在您的示例中,这是正确的,因为 k.getBytes()
返回平台默认字符集中的字节。
更频繁地,您需要指定编码。但是,有一种比您链接的问题更简单的方法。 String API 提供了在特定编码中在 String 和 byte[] 数组之间进行转换的方法。这些方法建议使用 CharsetEncoder/CharsetDecoder“当需要对解码 [编码] 过程进行更多控制时。”
要从特定编码的字符串中获取字节,可以使用同级 getBytes() 方法:
byte[] bytes = k.getBytes( StandardCharsets.UTF_8 );
要将具有特定编码的字节放入字符串,您可以使用不同的字符串构造函数:
String v = new String( bytes, StandardCharsets.UTF_8 );
请注意,ByteBuffer.array()
是可选操作。如果您使用数组构建了 ByteBuffer,则可以直接使用该数组。否则,如果您想安全起见,请使用ByteBuffer.get(byte[] dst, int offset, int length)
将字节从缓冲区获取到字节数组中。
【讨论】:
而在ByteBuffer.get
函数中,输入又是一个字节数组,我怎样才能得到它?再说一遍 k.getbytes 没有任何意义,不是吗?
@WilliamKinaan - 你有你提供给ByteBuffer.get(byte[] dst, int offset, int length)
的字节[]。您可以使用 String() 构造函数 `String(byte[] bytes, int offset, int length, Charset charset) 从中构建一个 String。您可以对两个调用使用相同的偏移量和长度值。
java.nio.ByteBuffer 中没有 k.getBytes() 方法(可能不在我使用的版本中)。所以我使用了 k.array() 方法,它会返回 byte[].
@MaduraPradeep - 在问题和这个答案的示例代码中,k
是一个字符串,而不是一个字节缓冲区。
请注意,UTF-8 可能不是将字节转换为字符串的最佳字符集,反之亦然。对于字节到字符的一对一映射,最好使用 ISO-8859-1,请参阅***.com/questions/9098022/…【参考方案3】:
试试这个:
new String(bytebuffer.array(), "ASCII");
注意。在不知道其编码的情况下,您无法正确地将字节数组转换为字符串。
希望对你有帮助
【讨论】:
UTF-8 可能是比 ASCII 更好的默认猜测? 两者都不应该被指定,因为 OP 使用 k.getBytes(),它使用平台的默认字符集。 并非所有缓冲区都由数组支持,因此.array()
可能会抛出异常。
并非所有字节缓冲区都支持.array()
方法。
小心!如果您使用array()
,您必须还使用arrayOffset()
在数组中的正确位置开始!这是一个微妙的陷阱,因为通常 arrayOffset() 为 0;但在极少数情况下,如果您不考虑它,您将获得难以发现的错误。【参考方案4】:
只是想指出,假设 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() 将始终为真或假,具体取决于您的用例。在实践中,除非您真的希望它在任何情况下都能正常工作,否则优化掉您不需要的分支是安全的。但其余答案可能不适用于通过 ByteBuffer.allocateDirect() 创建的 ByteBuffer。
【讨论】:
如果缓冲区是通过ByteBuffer.wrap(bytes, offset, size)
工厂创建的,.array()
将返回整个bytes
数组。最好使用程心勇建议的形式
Charset 上的 .decode() 是一个更好的解决方案,同意。我确实觉得我的答案的上下文是有用的信息,但现在更不用说了。
小心!如果您使用array()
,您必须还使用arrayOffset()
在数组中的正确位置开始!这是一个微妙的陷阱,因为通常 arrayOffset() 为 0;但在极少数情况下,如果你不考虑它,你会遇到难以发现的错误。【参考方案5】:
简单调用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 的回答。
【讨论】:
【参考方案6】:这个问题的根源是如何将字节解码为字符串?
这可以通过 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 缓冲区
然后我们可以将结果,例如,放在一个字符串中
【讨论】:
您的代码未从 latin1 解码为 utf8。虽然您的代码是正确的,但调用 CharBuffer utf8Buffer 有点误导,因为它没有编码。【参考方案7】:使用 Java 将 String 转换为 ByteBuffer,然后从 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:
こんにちは
ããã«ã¡ã¯
【讨论】:
【参考方案8】:请注意(除了编码问题),一些更复杂的链接代码会导致获取相关 ByteBuffer 的“活动”部分的麻烦(例如通过使用位置和限制),而不是简单地编码所有整个后备数组中的字节数(正如这些答案中的许多示例所做的那样)。
【讨论】:
【参考方案9】: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");
;
【讨论】:
【参考方案10】:这是一个将字节缓冲区转换为字符串的简单函数:
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;
【讨论】:
【参考方案11】:这是在 java.nio.ByteBuffer
实例上对我有用的唯一方法:
String fileContent = new String(bb.array(), StandardCharsets.UTF_8);
相关代码sn-p如下:
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);
【讨论】:
以上是关于Java ByteBuffer 到字符串的主要内容,如果未能解决你的问题,请参考以下文章