以下问题:我有一个大文本文件,每行包含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字节,以便原始行不会被分割...
答案 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
,您可以在其中明确控制从磁盘读入内存的内容。