用优化读取N行 - Java

时间:2014-02-16 08:04:11

标签: java optimization file-io readline

我有一个行N行的大文本文件。现在我必须在i次迭代中阅读这些行。这意味着我必须在一次迭代中读取n = Math.floor(N/i)行。现在,在每次迭代中,我必须填充n长度的字符串数组。所以基本的问题是我应该如何在最佳时间内阅读n行?最简单的方法是使用BufferedReader并使用BufferedReader.readLine()一次读取一行,但如果n太大,则会显着降低性能。有没有办法一次准确读取n行?

2 个答案:

答案 0 :(得分:1)

要从文本文件中读取n行,从系统的角度来看,除了必要的阅读尽可能多的字符之外别无他法,直到您看到n行尾分隔符(除非文件已被预处理以检测这些,但我怀疑这是允许的。)

据我所知,世界上没有任何文件I / O系统支持“直到nth某个字符出现”之前的函数,也不支持“n以下行”(但我可能错了。)

如果你真的想最大限度地减少I / O函数调用的次数,那么你的最后一种方法是使用块I / O,你可以用它来读取一个“页面”(比如预期的n倍或最大线长度),并自己检测行尾。

答案 1 :(得分:0)

我同意Yves Daoust的回答,除了推荐的段落

  

如果你真的想最小化I / O函数调用的数量,你的最后一种方法就是块I / O,你可以用它来读取一个“页面”(比如长度n倍于预期或最大行长度) ),并自己检测行尾。

没有必要“自己检测行尾”。像

这样的东西
new BufferedReader(new InputStreamReader(is, charset), 8192);

创建一个缓冲区为8192个字符的阅读器。问题是这对于读取块中的数据有多大用处。为此,我需要byte[],其间有一个sun.nio.cs.StreamDecoder我尚未调查过。

一定要使用

new BufferedReader(new InputStreamReader(new BufferedInputStream(is, 8192), charset));

所以你得到一个byte[]缓冲区。

请注意,8192是BufferedReaderInputStreamReader的默认大小,因此将其删除在上面的示例中不会改变任何内容。请注意,使用更大的缓冲区是没有意义的,甚至可能对性能有害。

更新

到目前为止,你得到了所需的所有缓冲,这应该足够了。如果没有,您可以尝试:

  • 避免解码器开销。当您的行被\n终止时,您可以在文件内容中查找(byte) \n而不对其进行解码(除非您使用了一些异国情调的Charset)。
  • 自己预取数据。通常,操作系统应该处理它,所以当你的缓冲区变空时,Java会调用操作系统,并且数据已经存储在内存中。
  • 使用内存映射文件,因此不需要OS调用来获取更多数据(因为创建映射时所有数据都“存在”)。