Java中从ByteBuffer获取字节数组

115

这是获取ByteBuffer中字节的推荐方式吗?

ByteBuffer bb =..

byte[] b = new byte[bb.remaining()]
bb.get(b, 0, b.length);
6个回答

123

这取决于你想要做什么。

如果你想要检索剩余的字节(在位置和限制之间),那么你所拥有的就可以工作。你也可以这样做:

ByteBuffer bb =..

byte[] b = new byte[bb.remaining()];
bb.get(b);

根据ByteBuffer的文档,两者是等价的。


6
正确。请注意,即使支持数组更长,bb.capacity()可能等于bb.remaining(),因此您不能使用它们的相等性作为测试bb.array()正确性的依据。请参见ByteBuffer.slice() - cdunn2001
1
请注意,为了避免更改缓冲区的位置,我使用了 bb.slice().remaining()。这样看起来就像是一个干净的转储,而不会触及原始缓冲区。 - Kyll
这个方法给我有符号的字节,但是我想要无符号的... 有什么想法吗? - H Raval
Java没有无符号整数的概念,只有有符号整数。如果要使用“无符号字节”,需要进行强制类型转换为 int 并使用位掩码:对于某个值 kint unsigned_byte = b[k] & 0xff; - Jason S
如果你想将整个缓冲区转换成字节数组,你需要先调用ByteBuffer#clear吗? - Kenny Worden

24

请注意,bb.array() 方法不考虑字节缓冲区的位置,如果你正在处理的字节缓冲区是其他缓冲区的片段,则可能会更糟。

也就是说,

byte[] test = "Hello World".getBytes("Latin1");
ByteBuffer b1 = ByteBuffer.wrap(test);
byte[] hello = new byte[6];
b1.get(hello); // "Hello "
ByteBuffer b2 = b1.slice(); // position = 0, string = "World"
byte[] tooLong = b2.array(); // Will NOT be "World", but will be "Hello World".
byte[] world = new byte[5];
b2.get(world); // world = "World"

这可能不是你想要做的事情。

如果你真的不想复制字节数组,一个解决方法是使用byte-buffer的arrayOffset() + remaining(),但前提是应用程序支持所需的字节缓冲区的索引+长度。


"bb.array()不遵循字节缓冲区的位置,您能为我们提供更多关于此部分的细节吗?我理解了切片示例,但需要更多有关bb.array()造成混乱的原因的细节。" - kkrishnaai

8
就这么简单
  private static byte[] getByteArrayFromByteBuffer(ByteBuffer byteBuffer) {
    byte[] bytesArray = new byte[byteBuffer.remaining()];
    byteBuffer.get(bytesArray, 0, bytesArray.length);
    return bytesArray;
}

这是一个很好的答案。我确认在这里使用了相同的逻辑:java.nio.channels.Channels.WritableByteChannelImpl.write(ByteBuffer)。有人知道这个答案是否有任何特殊的边界情况不能正常工作吗? - kevinarpe

4
final ByteBuffer buffer;
if (buffer.hasArray()) {
    final byte[] array = buffer.array();
    final int arrayOffset = buffer.arrayOffset();
    return Arrays.copyOfRange(array, arrayOffset + buffer.position(),
                              arrayOffset + buffer.limit());
}
// do something else

4

如果一个人对给定的(直接)ByteBuffer的内部状态一无所知,并且想要检索缓冲区的全部内容,可以使用以下方法:

ByteBuffer byteBuffer = ...;
byte[] data = new byte[byteBuffer.capacity()];
((ByteBuffer) byteBuffer.duplicate().clear()).get(data);

ByteBuffer.get(byte[]) returns a ByteBuffer - pyb
还有什么问题吗?不确定你的意思,抱歉。 - Tomáš Myšík
问题是如何从ByteBuffer转换为byte[]。 - pyb
3
一旦被调用,它们就在“data”变量中。获取器返回“this”,详见其Javadoc。 - Tomáš Myšík
谢谢,我没明白。由于get方法返回一个值,我没想到它也会有副作用。 - pyb

1
这是一种获取byte[]的简单方法,但使用ByteBuffer的部分重点是避免创建byte[]。也许您可以直接从ByteBuffer中获取所需内容,而无需先获取byte[]

17
但通常您需要调用一些接受byte[]的东西(不在您自己的代码中),因此转换是必须的。 - James Moore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接