我想知道如何在java中直接到达文本文件的特定行号。 一种方法就是这样。
int line=0;
BufferedReader read=new BufferedReader(new FileReader(Filename));
while(read.readLine()!=null){
line++;
if(line==LIMIT) break;
}
但这会创建很多String对象,除非gc运行,否则不会释放它们。 请提供一个快速且不会消耗大量内存的解决方案。
PS:我正在阅读一个有数百万行的文件。
答案 0 :(得分:2)
让我们假设文本文件具有可变长度的行,并且您没有预处理它来创建索引。 (否则,应该可以预先确定第N行的位置,然后"寻找它。)
首先观察到(在上述假设的情况下),如果不在第N行开始之前检查每个字符,就不可能找到第N行。
但你仍然可以通过不会产生大量垃圾的方式来做到这一点。这是一个简单的版本:
BufferedReader br = new BufferedReader(new FileReader(filename));
for (int i = 1; i < LIMIT; i++) {
while ((ch = br.read()) != '\n') {
if (ch == -1) {
// reached the end of file too soon ...
throw new IOException("The file has < " + LIMIT + " lines");
}
}
}
line = br.readLine();
诀窍是跳过线而不将它们形成String
个对象。
现在上面有一个小瑕疵。假设文本文件的行由换行符('\n'
)终止,而readLine
可以处理3种行分隔符。但这可以解决......而不会产生额外的垃圾。我会将其作为#34;练习给读者&#34;以及调查调整,例如使用read(char[])
代替read()
。
如果您使用FileInputStream
打开文件,获得FileChannel
,将字节读入ByteBuffer
,然后搜索(byte) '\n'
,则可能会获得更好的效果。但是代码要复杂得多。
但是,我想强调评论中的观点。你可能浪费你的时间。尽管产生了大量垃圾,但您的原始版本可能会运行得足够快。实际上,当垃圾与非垃圾的比例很高时,GC很快。对于一个读取丢弃线的程序,你几乎可以保证会出现这种情况。
与其花时间了解如何根据错误前提来快速制作程序,您最好编写一个简单版本并测量其在典型输入文件上的性能。只有在程序实际太慢时才进行优化。
答案 1 :(得分:0)
您可以读取块中的数据(可能是1024字节块)和搜索行字符,而不是读取字符串。要读取数据块,可以使用byte
数组,因此它将被重用,因此不会出现内存问题。你必须照顾:
\r
和\n
字符以块为单位而不是逐字节读取数据将更有效。
答案 2 :(得分:-2)
我认为这应该有所帮助:
FileReader fr = new FileReader("file1.txt");
BufferedReader br = new BufferedReader(fr);
LineIterator it = IOUtils.lineIterator(br);
for (int l = 0; it.hasNext(); l++) {
String line = (String) it.next();
if (l == LIMIT) {
return line;
}
}