如何将一定量的字节读入缓冲区?

时间:2011-11-19 12:37:22

标签: java performance buffer nio channel

以下问题:我有一个大文本文件,每行包含13个字节。我不想使用InputStream以常用方式逐行读取文件。我正在尝试使用NIO Channels和MappedByteBuffers来获得更好的性能和有限的资源。

所以这就是我到目前为止所做的事情:

RandomAccessFile data = new RandomAccessFile("the_file.txt", "rw");
FileChannel channel = data.getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, capacity);

这里容量是n * 13,以确保只有整行适合缓冲区。 但这不起作用!我像这样填充缓冲区:

int bytesRead = channel.read(buffer);

但这并没有填满整个缓冲区! bytesRead 不等于容量,在我的情况下更糟糕的是 bytesRead%13 不是,这意味着它不包含整行,最后切断了一些东西。 如何在缓冲区中读取一定数量的字节?在我的情况下,我需要n * 13字节,以便原始行不会被分割...

3 个答案:

答案 0 :(得分:2)

快速查看documentation,可以了解read方法的真相。

  

读取操作可能不会填充缓冲区,实际上它可能不会   完全读取任何字节。

由此可以很清楚,不能假设read调用将填充缓冲区。为了实现这一点,你需要创建一个循环,检查剩下多少就可以了:

while(buffer.remaining() > 0) channel.read(buffer);

在强大的java流API中,所有这些都是自动处理的。

我建议使用简单的BufferedReader,然后衡量效果。然后,您可以通过NIO课程再次尝试做出更明智的决定。您会对基于流的类的性能感到惊讶。此解决方案还将为您提供易于维护和阅读的代码。

答案 1 :(得分:1)

如果您有bytesRead%13!=0,则将新缓冲区映射到channel.map(FileChannel.MapMode.READ_WRITE, (bytesRead/13)*13, capacity);,并且不处理每个缓冲区的最后bytesRead%13

答案 2 :(得分:1)

如果您使用的是MappedByteBuffer,那么您也可以一次性映射整个文件。 Java和OS VM系统将根据需要将数据从磁盘读取到内存。它不会立即将整个文件读入内存,除非它真的很小。然后,您可以专注于您的代码,只需访问您感兴趣的每个循环/读取的字节范围。

到目前为止,您更详细,更复杂的方法(以及相应的答案)更适合传统的ByteBuffer,您可以在其中明确控制从磁盘读入内存的内容。