Java:读取HUGE文件的最后n行

Gau*_*rma 36 java file-io large-files

我想读取一个非常大的文件的最后n行,而不是使用Java将整个文件读入任何缓冲区/内存区域.

我查看了JDK API和Apache Commons I/O,但无法找到适合此目的的API.

我在想UNIX中的尾部或更少的方式.我不认为他们加载整个文件,然后显示该文件的最后几行.在Java中也应该有类似的方法来做同样的事情.

小智 28

我发现它用做最简单的方法ReversedLinesFileReader,从Apache的百科全书-io的 API.此方法将为您提供从文件的底部到顶部的行,您可以指定n_lines值以指定行数.

import org.apache.commons.io.input.ReversedLinesFileReader;


File file = new File("D:\\file_name.xml");
int n_lines = 10;
int counter = 0; 
ReversedLinesFileReader object = new ReversedLinesFileReader(file);
while(counter < n_lines) {
    System.out.println(object.readLine());
    counter++;
}
Run Code Online (Sandbox Code Playgroud)

  • 注意:每次调用`readLine()`时,光标前进.所以这段代码实际上会错过其他每一行,因为`while`语句中的`readLine()`的输出没有被捕获. (6认同)
  • @aapierce你和vinksharma的评论已经过时了,对吧?Mise的编辑解决了我猜的问题.当评论不符合帖子本身的当前版本时,这有点令人困惑. (3认同)
  • 此代码有点错误,因为readLine()被调用两次.如aapierce所述.但是完全指向ReversedLinesFileReader (2认同)

pax*_*blo 27

如果使用a RandomAccessFile,则可以使用lengthseek到达文件末尾附近的特定点,然后从那里向前读取.

如果您发现没有足够的线路,请从该点备份并重试.一旦你弄明白N最后一行开始的地方,你就可以找到那里,只需阅读和打印.

可以根据您的数据属性进行初始最佳猜测假设.例如,如果它是一个文本文件,则行长度可能不会超过132的平均值,因此,要获得最后五行,请在结束前开始660个字符.然后,如果你错了,请在1320再试一次(你甚至可以使用你从最后660个字符中学到的东西来调整它 - 例如:如果那些660个字符只是三行,下一个尝试可能是660/3*5,加上可能有点额外的以防万一).


Ste*_*n C 19

如其他答案所述,RandomAccessFile是一个很好的起点.但有一个重要的警告.

如果您的文件没有使用每个字符一个字节的编码进行编码,则该readLine()方法不适用于您.并且readUTF()在任何情况下都不会起作用.(它读取一个以字符数开头的字符串......)

相反,您需要确保以一种尊重编码字符边界的方式查找行尾标记.对于固定长度编码(例如UTF-16或UTF-32的风格),您需要从字节位置开始提取字符,这些字符位置可以按字节大小整除.对于可变长度编码(例如UTF-8),您需要搜索必须是字符的第一个字节的字节.

以UTF-8的情况下,一个字符的第一个字节将是0xxxxxxx110xxxxx1110xxxx11110xxx.其他任何东西都是第二个/第三个字节,或者是非法的UTF-8序列.请参阅Unicode标准,版本5.2,第3.9章,表3-7.这意味着,正如评论讨论所指出的,正确编码的UTF-8流中的任何0x0A和0x0D字节将表示LF或CR字符.因此,如果我们可以假设不使用其他类型的Unicode行分隔符(0x2028,0x2029和0x0085),那么简单地计算0x0A和0x0D字节是一种有效的实现策略(对于UTF-8).你不能假设,那么代码会更复杂.

确定了正确的字符边界后,您可以调用new String(...)传递字节数组,偏移量,计数和编码,然后重复调用String.lastIndexOf(...)以计算行尾.


Tor*_*mon 5

ReversedLinesFileReader可以在发现Apache的百科全书IO java库。

    int n_lines = 1000;
    ReversedLinesFileReader object = new ReversedLinesFileReader(new File(path));
    String result="";
    for(int i=0;i<n_lines;i++){
        String line=object.readLine();
        if(line==null)
            break;
        result+=line;
    }
    return result;
Run Code Online (Sandbox Code Playgroud)