成长ByteBuffer

时间:2009-11-21 05:54:03

标签: java bytebuffer

有没有人见过java.nio.ByteBuffer的实现,如果putX()调用超出容量,它将动态增长?

我想这样做的原因有两个:

  1. 我不知道我需要多少空间。
  2. 每次空间不足时,我宁愿不再使用新的ByteBuffer.allocate(),而是使用批量put()。

11 个答案:

答案 0 :(得分:33)

为了使异步I / O工作,您必须具有连续的内存。在C中,您可以尝试重新分配数组,但在Java中,您必须分配新内存。您可以写入ByteArrayOutputStream,然后在准备发送时将其转换为ByteBuffer。缺点是你正在复制内存,高效IO的关键之一是减少内存复制的次数。

答案 1 :(得分:9)

ByteBuffer无法真正以这种方式工作,因为它的设计理念只是特定数组的视图,您也可以直接引用它。它没有尝试将该数组交换为更大的数组,而不会发生奇怪的事情。

您想要使用的是DataOutput。最方便的方法是使用(预发布)Guava库:

ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.write(someBytes);
out.writeInt(someInt);
// ...
return out.toByteArray();

但您也可以手动从ByteArrayOutputStream创建DataOutputStream,只需通过将它们链接到AssertionErrors来处理虚假的IOExceptions。

答案 2 :(得分:6)

看看Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html这是一个替代品(它包装了ByteBuffer)

但是,我建议你分配超过你需要的东西,不要太担心它。如果你分配一个缓冲区(特别是一个直接缓冲区),操作系统会为它提供虚拟内存,但它只在实际使用时才使用物理内存。虚拟内存应该非常便宜。

答案 3 :(得分:5)

另一种选择是使用具有大缓冲区的直接内存。这会消耗虚拟内存,但仅使用与您使用的物理内存一样多的数据(按页面通常为4K)

因此,如果您分配1 MB的缓冲区,它会占用1 MB的虚拟内存,但是唯一的操作系统会为实际使用的应用程序提供物理页面。

效果是你看到你的应用程序使用了大量的虚拟内存,但只有相对少量的常驻内存。

答案 4 :(得分:4)

看看Netty的DynamicChannelBuffer也许值得一看。我觉得方便的事情是:

  • slice(int index, int length)
  • 未签名的操作
  • 分隔的作者和读者索引

答案 5 :(得分:1)

我建议使用输入流从文件接收数据(如果需要非阻塞,则使用一个独立的线程),然后将字节读取到ByteArrayOutstream中,这使您能够将其作为字节数组获取。这是一个简单的示例,没有添加太多解决方法。

    try (InputStream inputStream = Files.newInputStream(
            Paths.get("filepath"), StandardOpenOption.READ)){

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int byteRead = 0;

        while(byteRead != -1){
            byteRead = inputStream.read();
            baos.write(byteRead);
        }
        ByteBuffer byteBuffer = ByteBuffer.allocate(baos.size())
        byteBuffer.put(baos.toByteArray());

        //. . . . use the buffer however you want

    }catch(InvalidPathException pathException){
        System.out.println("Path exception: " + pathException);
    }
    catch (IOException exception){
        System.out.println("I/O exception: " + exception); 
    }

答案 6 :(得分:0)

实际上,自动扩展缓冲区使用起来更加直观。如果你能负担得起重新分配的性能,那么为什么你不会这样做呢?

Netty' ByteBuf给出了这一点。就像他们已经java.nio ByteBuffer一样,刮掉了边缘,使其更容易使用。

此外,还有on Maven in an independent netty-buffer个套餐,因此您无需包含完整的Netty套件即可使用。

答案 7 :(得分:0)

另一个解决方案是分配足够的内存,填充ByteBuffer,然后仅返回占用的字节数组:

初始化大的ByteBuffer

ByteBuffer byteBuffer = ByteBuffer.allocate(1000);

放完东西后:

private static byte[] getOccupiedArray(ByteBuffer byteBuffer)
{
    int position = byteBuffer.position();
    return Arrays.copyOfRange(byteBuffer.array(), 0, position);
}

但是,从一开始就使用org.apache.commons.io.output.ByteArrayOutputStream可能是最好的解决方案。

答案 8 :(得分:0)

Netty ByteBuf对此非常好。

答案 9 :(得分:-4)

Vector允许持续增长

  

Vector<Byte> bFOO = new Vector<Byte>(); bFOO.add((byte)0x00);`

答案 10 :(得分:-6)

要序列化某些东西,您需要输入对象。你可以做的是将你的对象放在对象的集合中,然后make循环来获取迭代器并将它们放在字节数组中。然后,致电ByteBuffer.allocate(byte[].length)。这就是我所做的,它对我有用。