使用 Bytebuffer 写出与简单写出的返回不同

Posted

技术标签:

【中文标题】使用 Bytebuffer 写出与简单写出的返回不同【英文标题】:Writing out using a Bytebuffer returns differently from simple write out 【发布时间】:2013-04-17 17:56:54 【问题描述】:

我正在尝试将字节数据写入文件并对其进行优化,我想减少写入文件的次数。

目前,我正在使用:

try (RandomAccessFile out = new RandomAccessFile(file, "rw")) 

    for(int i = 0; i < totalPkts; i++) 
        out.writeInt(data.get(i));
    

这很好用,但是很慢,因为有很多 out.write 调用。

所以我改用ByteBuffer 代替写出:

try (RandomAccessFile out = new RandomAccessFile(file, "rw")) 
    ByteBuffer buffer = ByteBuffer.allocate(totalPkts*4); // prevent BufferOverflow

    for(int i = 0; i < totalPkts; i++) 
        buffer.putInt(data.get(i));
    
    out.write(buffer.array());

两种方法生成的文件大小不同。 ByteBuffer 文件几乎比正常输出文件大一 mb。这可以解释为什么差异会说它们不一样。

我尝试使用 DataOutputStream,结果是一样的。 使用ByteBuffer 编写的文件仍然比不使用ByteBuffer 的文件大1mb。

【问题讨论】:

【参考方案1】:

使用 ByteBuffer 编写的文件较大的原因是因为您如何初始化 ByteBuffer。当您简单地使用writeInt(int) 进行写入时,您只是在写入您需要写入的数据。但是,当您创建 ByteBuffer 时,您创建的它比我理解的防止溢出所需的大。但是,这也意味着底层数组,即从 array() 方法返回的数组,也比它需要的大。由于数组不了解位置和限制,所以当你写数组时,所有的数据之后的空白空间都会被写入,导致文件很大。您需要做的是将所有数据放入缓冲区后,您需要翻转缓冲区,然后创建一个长度与缓冲区的limit() 相同的新数组(翻转一次),然后get(byte[])缓冲区中的所有数据。一旦你有了 那个 数组,你就需要编写它。

这就是我要说的:

try (RandomAccessFile out = new RandomAccessFile(file, "rw")) 
    ByteBuffer buffer = ByteBuffer.allocate(totalPkts*4);

    for(int i = 0; i < totalPkts; i++) 
        buffer.putInt(data.get(i));
    

    buffer.flip();
    byte[] data = new byte[buffer.limit()];
    buffer.get(data);
    out.write(data);

【讨论】:

很好的答案!这就是我要找的。​​span> 【参考方案2】:

如果您想减少写入量,请考虑使用字节数组写入文件流。 (前提是 data 变量中的数据可以转换为字节)。至于不一样,请检查您是否在某个时候刷新流并在程序终止之前正确关闭它。

【讨论】:

ByteBuffer 缓冲区 = ByteBuffer.allocate(totalPkts*4); // 为什么需要 totalPkts*4,为什么不只需要 totalPkts? 否则我会得到 BufferOverflowException。一个 int 是 4 个字节。

以上是关于使用 Bytebuffer 写出与简单写出的返回不同的主要内容,如果未能解决你的问题,请参考以下文章

教你写出高性能 JavaScript

在Java中,ArrayList与数组如何相互转换,写出例子

简述啥是SQL注入,写出简单的SQL注入语句

Java--Stream,NIO ByteBuffer,NIO MappedByteBuffer性能对比

使用Groovy+Spock轻松写出更简洁的单测

如何在 C# 中使用 UTF-8 以外的代码页写出文本文件?