Java BufferedReader如何将文本文件指针回到顶部?

26

我目前有两个BufferedReader对象,它们都初始化在同一个文本文件上。当我使用第一个BufferedReader读完这个文本文件后,我需要使用第二个BufferedReader从头再次对这个文件进行读取。多次从同一文件中读取数据是必要的。

我知道有reset()方法,但是在使用之前需要调用mark()方法,并且mark()方法需要知道文件的大小,这是我认为不必要的。

有什么想法吗? 包? 库? 代码?

谢谢 TJ

5个回答

29

缓冲读取器适用于按顺序读取文件。您需要使用java.io.RandomAccessFile,然后可以使用seek()将您带到文件中想要的位置。

随机访问读取器的实现方式如下:

try{
     String fileName = "c:/myraffile.txt";
     File file = new File(fileName);
     RandomAccessFile raf = new RandomAccessFile(file, "rw");
     raf.readChar();
     raf.seek(0);
} catch (FileNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
} catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
}

"rw"是一种模式字符,详细介绍了该字符的用法。

顺序访问读取器设置成这样是为了让它们实现缓冲,并且防止在其操作下改变数据。例如,给缓冲读取器的文件读取器只能由该缓冲读取器操作。如果还有其他位置可以影响它,则可能会导致不一致的操作,因为一个读取器在文件读取器中推进其位置,而另一个读取器希望其位置保持不变。现在使用另一个读取器时,该读取器处于一个不确定的位置。


26

单纯创建一个新的 BufferedReader 来从文件顶部读取有什么缺点吗?如果文件足够小,我会期望操作系统会缓存文件。

如果你担心性能问题,你是否已经证明它成为瓶颈了呢?我会选择最简单的方式来做,并且在有具体原因之前不去担心它。我的意思是,你可以将整个文件读入内存,然后对结果进行两遍操作,但这比只是用新的阅读器从开头再次读取要复杂一些。


3

最好的方法是改变你的算法,以一种不需要第二遍扫描的方式。当我需要处理巨大的文件(但不是非常可怕,即几GB)而内存不足时,我曾经使用过这种方法。

这可能很难,但性能的提升通常值得努力。


你能详细说明一下吗?我有一个30MB大小的文件,无法将其全部加载到内存中。我已经对数据进行了排序,现在想直接在文件上进行二分查找。为此,我需要进行随机寻址。 - over_optimistic
现在假设你的意思是30GB,除非你使用真正小型嵌入式硬件(但那样就没有磁盘了)。无论如何,在磁盘上随机搜索往往会完全破坏二分搜索的对数性能。一些可选方案是:1)进行顺序访问(是的,在磁盘上顺序搜索可能比二分搜索更快),或者2)使用B树等混合方法。如果这些提示不够用,您可能需要将问题单独提出来,而不是作为评论(请在此处发布带有问题链接的评论以引起我的注意)。 - Davide

1
关于标记/重置:
BufferedReader中的mark方法需要一个readAheadLimit参数,该参数限制了在标记之后读取多远后重置变得不可能。重置并不意味着文件系统的seek(0),它只是在缓冲区内寻找。引用Javadoc的话:
“readAheadLimit - 可以在保留标记的同时读取的字符数限制。在读取这么多字符后,尝试重置流可能会失败。如果限制值大于输入缓冲区的大小,则会分配一个新的缓冲区,其大小不小于限制。因此,应谨慎使用大值。”

-1
整个BufferedReader中关于mark()和reset()的设计都有些不太好。
为什么不扩展这个类,在构造函数中执行mark(),然后在topOfFile()方法中执行seek(0)呢?
敬礼, ~A

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接