有没有人见过java.nio.ByteBuffer的实现,如果putX()调用超出容量,它将动态增长?
我想这样做的原因有两个:
答案 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)
。这就是我所做的,它对我有用。