如何从ByteBuffer中提取已使用的字节数组?

6

java.nio.ByteBuffer 类有一个 ByteBuffer.array() 方法,但此方法返回的数组大小等于缓冲区容量而非已使用容量。因此,我遇到了一些问题。

我分配了一个指定大小的 ByteBuffer,并向其插入数据。

ByteBuffer oldBuffer = ByteBuffer.allocate(SIZE);
addHeader(oldBuffer, pendingItems);
newBuffer.flip();
oldBuffer.put(newBuffer);
// as of now I am sending everything from oldBuffer
send(address, oldBuffer.array());

我该如何仅发送oldBuffer中正在使用的内容?是否有一行代码可以实现这个功能?


修改您的 send() 方法以接受长度(和偏移量)或将实际的 ByteBuffer 作为参数传递会更简单。您不应该像这样复制数据。 - user207421
2个回答

8
你可以翻转缓冲区,然后创建一个新的数组以填充缓冲区中剩余的大小。
oldBuffer.flip();
byte[] remaining = new byte[oldBuffer.remaining()];
oldBuffer.get(remaining);

使用 flip()Arrays.copyOf 的一行代码实现另一种方式。

oldBuffer.flip();
Arrays.copyOf(oldBuffer.array(), oldBuffer.remaining());

没有 flip() 的情况下

Arrays.copyOf(oldBuffer.array(), oldBuffer.position());

正如EJP所说,如果您可以访问send(..)方法,您可以向send()方法添加大小和偏移参数,避免创建和填充新数组的需要。


是的,我确实可以访问send方法,那么我们能做哪些更改呢?你能提供一个例子来让我清楚吗? - flash
这取决于您如何在send方法中处理数据,如果您最终需要该长度的数组,则可以通过这种方式完成,并且只需调用send(..)方法而不修改任何内容。此外,如果数据不是那么多,您可以直接复制该数组。 - Jose Da Silva
是的,我确实需要在发送方法中使用该长度的字节数组。另外,“带 flip() 版本”和“不带 flip() 版本”有什么区别? - flash
如果迟早你需要那个长度的数组,那么最好现在就创建。Flip() 函数会改变 ByteBuffer 的限制、位置和标记值,通常在读取之前使用。数组是相同的,所以实际上没有太大的区别,如果你不再使用该缓冲区,那么根本没有区别。 - Jose Da Silva

2

position() 方法可以获取缓冲区中已经被使用的数据量。

因此,需要创建一个相应大小的字节数组。

接下来,将缓存区位置设置为 0,因为需要从那里读取数据。用 rewind() 方法实现。

然后,使用 get() 方法将缓冲区中的数据复制到数组中。

byte[] data = new byte[buffer.position()];
buffer.rewind();
buffer.get(data);

请注意,仅当buffer.hasArray()返回true时,buffer.array()才有效。因此,在调用之前,请检查hasArray()。否则,buffer.array()将抛出以下任何一种异常。
  1. UnsupportedOperationException - 在直接缓冲区上调用它时。
  2. ReadOnlyBufferException - 如果缓冲区是只读的。
"最初的回答"

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