Java 不断增长的 ByteBuffer
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1774651/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Growing ByteBuffer
提问by Seth
Has anyone has ever seen an implementation of java.nio.ByteBuffer that will grow dynamically if a putX() call overruns the capacity?
有没有人见过 java.nio.ByteBuffer 的实现,如果 putX() 调用超出容量,它会动态增长?
The reason I want to do it this way is twofold:
我想这样做的原因有两个:
- I don't know how much space I need ahead of time.
- I'd rather not do a new ByteBuffer.allocate() then a bulk put() every time I run out of space.
- 我不知道我需要提前多少空间。
- 我宁愿不做一个新的 ByteBuffer.allocate() ,然后每次用完空间时都做一个批量 put() 。
采纳答案by brianegge
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.
为了让异步 I/O 工作,你必须有连续的内存。在 C 中你可以尝试重新分配一个数组,但在 Java 中你必须分配新的内存。您可以写入 a ByteArrayOutputStream
,然后ByteBuffer
在准备发送时将其转换为 a 。缺点是您正在复制内存,而高效 IO 的关键之一是减少复制内存的次数。
回答by Peter Lawrey
Have a look at Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.htmlwhich is a drop in replacement (it wraps the ByteBuffer)
看看 Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html这是一个替代品(它包装了 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.
但是,我建议你分配比你需要的更多,不要太担心。如果您分配一个缓冲区(尤其是直接缓冲区),操作系统会为其提供虚拟内存,但仅在实际使用时才使用物理内存。虚拟内存应该很便宜。
回答by Kevin Bourrillion
A ByteBuffer cannot really work this way, as its design concept is to be just a viewof 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.
ByteBuffer 不能真正以这种方式工作,因为它的设计概念只是一个特定数组的视图,您也可以直接引用它。它无法尝试将该数组交换为更大的数组而不会发生奇怪的事情。
What you want to use is a DataOutput
. The most convenient way is to use the (pre-release) Guava library:
您要使用的是一个DataOutput
. 最方便的方法是使用(预发布)Guava 库:
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.
但是您也可以手动从 ByteArrayOutputStream 创建一个 DataOutputStream,并通过将它们链接到 AssertionErrors 来处理虚假的 IOExceptions。
回答by anonymous
It may be also worth to have a look at Netty's DynamicChannelBuffer. Things that I find handy are:
看看 Netty 的DynamicChannelBuffer也可能是值得的。我觉得方便的事情是:
slice(int index, int length)
- unsigned operations
- separated writer and reader indexes
slice(int index, int length)
- 无符号操作
- 分离的作者和读者索引
回答by Peter Lawrey
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)
另一种选择是使用带有大缓冲区的直接内存。这会消耗虚拟内存,但仅使用您使用的物理内存(按页面,通常为 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.
因此,如果您分配 1 MB 的缓冲区,它会占用 1 MB 的虚拟内存,但唯一的操作系统将物理页面提供给实际使用的应用程序。
The effect is you see your application using alot of virtual memory but a relatively small amount of resident memory.
结果是您看到您的应用程序使用了大量虚拟内存,但驻留内存量相对较少。
回答by user3436792
A Vector allows for continuous growth
Vector 允许持续增长
Vector<Byte> bFOO = new Vector<Byte>();
bFOO.add((byte) 0x00);`
Vector<Byte> bFOO = new Vector<Byte>();
bFOO.add((byte) 0x00);`
回答by user4358285
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.
要序列化某些东西,您将需要条目中的对象。您可以做的是将您的对象放在对象集合中,然后进行循环以获取迭代器并将它们放入字节数组中。然后,调用ByteBuffer.allocate(byte[].length)
。这就是我所做的,它对我有用。
回答by antak
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.
Netty'sByteBuf
正是为您提供了这一点。就像他们去掉了java.nio
'sByteBuffer
并刮掉了边缘,使其更易于使用。
Furthermore, it's on Maven in an independent netty-buffer
package so you don't need to include the full Netty suite to use.
此外,它位于 Maven 上的一个独立netty-buffer
包中,因此您无需包含完整的 Netty 套件即可使用。
回答by Full Stack
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.
我建议使用输入流从文件接收数据(如果您需要非阻塞,则使用独立线程)然后将字节读入 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);
}
回答by BullyWiiPlaza
Another solution for this would be to allocate more than enough memory, fill the ByteBuffer
and then only return the occupied byte array:
另一个解决方案是分配足够多的内存,填充ByteBuffer
然后只返回占用的字节数组:
Initialize a big ByteBuffer
:
初始化一个 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.
但是,org.apache.commons.io.output.ByteArrayOutputStream
从一开始就使用 a可能是最好的解决方案。