在 Java 中将 ByteBuffer 转换为字符串
Posted
技术标签:
【中文标题】在 Java 中将 ByteBuffer 转换为字符串【英文标题】:Convert ByteBuffer to String in Java 【发布时间】:2015-03-22 03:36:45 【问题描述】:我有一个来自ByteBuffer
的byte[] bytes
,其中包含一个数据包。我想将数据包放入String
。
目前我有以下
byte[] bytes = packet.array();
System.out.println("Packet String:" + new String(bytes));
但我最终得到以下输出
Packet String:E����<Ҧ@��@�.
03-22 04:30:28.187 9296-10152/willem.com.*** I/System.out﹕ ����J�j���k�:����������9�������
03-22 04:30:28.197 9296-10152/willem.com.*** I/System.out﹕ ��&�4��������ddrarpa��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
我试过这样编码
System.out.println("Packet String:" + new String(bytes, Charset.forName("UTF-8")));
但这不是正确的字符集。谁能告诉我是什么?
【问题讨论】:
没有人 可以告诉您您自己的文件的正确字符集是什么。只有您或编写它的软件才能产生这种效果。 以下reference on JAVA NIO ByteBuffer Basic Usage 解释了您阅读garbaje 的原因。 【参考方案1】:您需要使用缓冲区的位置和限制来确定要读取的字节数。
// ...populate the buffer...
buffer.flip(); // flip the buffer for reading
byte[] bytes = new byte[buffer.remaining()]; // create a byte array the length of the number of bytes written to the buffer
buffer.get(bytes); // read the bytes that were written
String packet = new String(bytes);
在我看来,你根本不应该使用支持array()
;这是不好的做法。直接字节缓冲区(由ByteBuffer.allocateDirect()
创建的没有后备数组,并且在您尝试调用ByteBuffer.array()
时会抛出异常。因此,为了可移植性,您应该尝试使用标准缓冲区get
和@ 987654326@ 方法。当然,如果你真的想使用数组,你可以使用ByteBuffer.hasArray()
来检查缓冲区是否有后备数组。
【讨论】:
然后我得到一个java.nio.BufferUnderflowException
并且字符串仍然没有意义
听起来您可能需要先致电flip
。写入缓冲区时,在再次读取之前,您通常需要调用flip
来重置位置和限制。 flip
会将位置设置为0
,并将限制设置为当前position
,从而使remaining
等于写入缓冲区的字节数。
我需要在哪里调用它?
通常你应该在写入缓冲区之后调用flip
。 flip
用于在缓冲区的写入和读取之间切换。写入字节时,缓冲区的位置会提前。为了从中读取,您需要 flip
缓冲区从头开始读取。 ByteBuffer
API 有点混乱,可能需要一段时间才能理解。
我会说你需要调用flip()
之前任何读取缓冲区,然后立即调用compact()
。保持缓冲区始终准备好写入(和读取)是最简单的,并且只让它们处于翻转状态的时间越短越好。【参考方案2】:
关于从位置到极限的设置范围的答案在一般情况下是不正确的。当缓冲区已被部分消耗或引用数组的一部分时(您可以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 的回答。
【讨论】:
这是对我有用的解决方案。谢谢。【参考方案3】:您忽略了缓冲区的limit
。你应该flip()
缓冲区,然后调用
new String(buffer.array(), 0, buffer.position())
然后重置它。
但您确实应该使用Charset
解码器来为此生成CharBuffer
。至少您应该为String
构造函数指定一个字符集。
【讨论】:
您创建它,调用CharsetDecoder.decode(ByteBuffer)
生成CharBuffer,
,然后将其直接转换为String.
但我不知道该使用什么字符集,我该如何找到?
了解任意字节数组的字符集并不是一个好方法。你需要提前知道那件事。有一些像 Apache Tika 这样的库可以提供字符集的猜测,但与任何格式猜测一样,这是一门不完善的科学。
应该指定编码,但更严重的是 buffer.limit() 是一个偏移量,而不是长度。构造函数希望使用字节长度。
You should flip() the buffer, then call
这会将位置重置为零。因此,new String(buffer.array(), 0, buffer.position())
将不起作用。【参考方案4】:
ByteBuffer 数据 = ...
新字符串(data.array() , "UTF-8");
【讨论】:
以上是关于在 Java 中将 ByteBuffer 转换为字符串的主要内容,如果未能解决你的问题,请参考以下文章
如何在 JNI 中将 char[] 转换为 ByteBuffer?
如何在 Kotlin 中将数据类转换为 ByteBuffer?