不断增长的字节缓冲区

发布于 2024-08-11 11:41:40 字数 183 浏览 5 评论 0原文

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

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

  1. 我不知道提前需要多少空间。
  2. 我不想每次用完空间时都先执行 new ByteBuffer.allocate() 然后执行批量 put() 。

Has anyone has ever seen an implementation of java.nio.ByteBuffer that will grow dynamically if a putX() call overruns the capacity?

The reason I want to do it this way is twofold:

  1. I don't know how much space I need ahead of time.
  2. I'd rather not do a new ByteBuffer.allocate() then a bulk put() every time I run out of space.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

書生途 2024-08-18 11:41:41

也值得看看 Netty 的 DynamicChannelBuffer。我发现方便的事情是:

  • slice(int index, int length)
  • 无符号操作
  • 分离写入器和读取器索引

It may be also worth to have a look at Netty's DynamicChannelBuffer. Things that I find handy are:

  • slice(int index, int length)
  • unsigned operations
  • separated writer and reader indexes
霊感 2024-08-18 11:41:41

事实上,自动扩展缓冲区的使用起来更加直观。如果您能负担得起重新分配的性能奢侈,为什么不呢!

Netty 的 ByteBuf 为您提供了准确的信息这。就像他们已经采用了 java.nio 的 ByteBuffer 并刮掉了边缘,使其更易于使用。

此外,它是在Maven上的一个独立的netty-buffer 包,因此您无需包含完整的 Netty 套件即可使用。

Indeed, auto-extending buffers are so much more intuitive to work with. If you can afford the performance luxury of reallocation, why wouldn't you!?

Netty's ByteBuf gives you exactly this. It's like they've taken java.nio's ByteBuffer and scraped away the edges, making it much easier to use.

Furthermore, it's on Maven in an independent netty-buffer package so you don't need to include the full Netty suite to use.

冷夜 2024-08-18 11:41:41

我建议使用输入流从文件接收数据(如果需要非阻塞,则使用单独的线程),然后将字节读入 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); 
    }

I'd suggest using an input stream to receive data from a file (with a sperate thread if you need non-blocking) then read bytes into a ByteArrayOutstream which gives you the ability to get it as a byte array. Heres a simple example without adding too many workarounds.

    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); 
    }
清晨说晚安 2024-08-18 11:41:41

另一个解决方案是分配足够的内存,填充 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 可能是最好的解决方案。

Another solution for this would be to allocate more than enough memory, fill the ByteBuffer and then only return the occupied byte array:

Initialize a big ByteBuffer:

ByteBuffer byteBuffer = ByteBuffer.allocate(1000);

After you're done putting things into it:

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

However, using a org.apache.commons.io.output.ByteArrayOutputStream from the start would probably be the best solution.

与他有关 2024-08-18 11:41:41

Netty ByteBuf 在这方面做得非常好。

Netty ByteBuf is pretty good on that.

茶色山野 2024-08-18 11:41:41

Vector 允许持续增长

向量<字节> bFOO = new Vector();
bFOO.add((字节)0x00);`

A Vector allows for continuous growth

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

汐鸠 2024-08-18 11:41:41

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

To serialize somethiing you will need object in entry. What you can do is put your object in collection of objects, and after that make loop to get iterator and put them in byte array. Then, call ByteBuffer.allocate(byte[].length). That is what I did and it worked for me.

山色无中 2024-08-18 11:41:40

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

In order for asynchronous I/O to work, you must have continuous memory. In C you can attempt to re-alloc an array, but in Java you must allocate new memory. You could write to a ByteArrayOutputStream, and then convert it to a ByteBuffer at the time you are ready to send it. The downside is you are copying memory, and one of the keys to efficient IO is reducing the number of times memory is copied.

何其悲哀 2024-08-18 11:41:40

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

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

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

但您也可以从 ByteArrayOutputStream 手动创建 DataOutputStream,然后通过将虚假 IOException 链接到 AssertionError 来处理它们。

A ByteBuffer cannot really work this way, as its design concept is to be just a view of a specific array, which you may also have a direct reference to. It could not try to swap that array for a larger array without weirdness happening.

What you want to use is a DataOutput. The most convenient way is to use the (pre-release) Guava library:

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

But you could also create a DataOutputStream from a ByteArrayOutputStream manually, and just deal with the spurious IOExceptions by chaining them into AssertionErrors.

假面具 2024-08-18 11:41:40

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

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

结果是您看到您的应用程序使用了大量虚拟内存,但驻留内存相对较少。

Another option is to use direct memory with a large buffer. This consumes virtual memory but only uses as much physical memory as you use (by page which is typically 4K)

So if you allocate a buffer of 1 MB, it comsumes 1 MB of virtual memory, but the only OS gives physical pages to the application which is actually uses.

The effect is you see your application using alot of virtual memory but a relatively small amount of resident memory.

紫罗兰の梦幻 2024-08-18 11:41:40

看看 Mina IOBuffer https://mina。 apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html 这是替换的下降(它包装了 ByteBuffer)

但是,我建议您分配比您需要的更多的内容,不用担心关于它太多了。如果您分配一个缓冲区(尤其是直接缓冲区),操作系统会为其提供虚拟内存,但它仅在实际使用时使用物理内存。虚拟内存应该非常便宜。

Have a look at Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html which is a drop in replacement (it wraps the ByteBuffer)

However , I suggest you allocate more than you need and don't worry about it too much. If you allocate a buffer (esp a direct buffer) the OS gives it virtual memory but it only uses physical memory when its actually used. Virtual memory should be very cheap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文