当前位置:  开发笔记 > 编程语言 > 正文

快速阅读文本文件的最后一行?

如何解决《快速阅读文本文件的最后一行?》经验,为你挑选了3个好方法。

从Java中的[非常非常大的]文件中读取最后一行文本的最快捷,最有效的方法是什么?



1> Eric Leschin..:

下面是两个函数,一个返回文件的最后一个非空行而不加载或单步执行整个文件,另一个返回文件的最后N行而不单步执行整个文件:

尾巴的作用是直接缩放到文件的最后一个字符,然后逐个字符地逐个字符,记录它看到的内容,直到找到换行符.一旦找到换行符,它就会突破循环.反转记录的内容并将其抛入字符串并返回.0xA是新行,0xD是回车符.

如果您的行结尾是\r\n或者是crlf其他"双换行样式换行符",则必须指定n*2行才能获得最后n行,因为它为每行计算2行.

public String tail( File file ) {
    RandomAccessFile fileHandler = null;
    try {
        fileHandler = new RandomAccessFile( file, "r" );
        long fileLength = fileHandler.length() - 1;
        StringBuilder sb = new StringBuilder();

        for(long filePointer = fileLength; filePointer != -1; filePointer--){
            fileHandler.seek( filePointer );
            int readByte = fileHandler.readByte();

            if( readByte == 0xA ) {
                if( filePointer == fileLength ) {
                    continue;
                }
                break;

            } else if( readByte == 0xD ) {
                if( filePointer == fileLength - 1 ) {
                    continue;
                }
                break;
            }

            sb.append( ( char ) readByte );
        }

        String lastLine = sb.reverse().toString();
        return lastLine;
    } catch( java.io.FileNotFoundException e ) {
        e.printStackTrace();
        return null;
    } catch( java.io.IOException e ) {
        e.printStackTrace();
        return null;
    } finally {
        if (fileHandler != null )
            try {
                fileHandler.close();
            } catch (IOException e) {
                /* ignore */
            }
    }
}

但是你可能不想要最后一行,你想要最后N行,所以请改用它:

public String tail2( File file, int lines) {
    java.io.RandomAccessFile fileHandler = null;
    try {
        fileHandler = 
            new java.io.RandomAccessFile( file, "r" );
        long fileLength = fileHandler.length() - 1;
        StringBuilder sb = new StringBuilder();
        int line = 0;

        for(long filePointer = fileLength; filePointer != -1; filePointer--){
            fileHandler.seek( filePointer );
            int readByte = fileHandler.readByte();

             if( readByte == 0xA ) {
                if (filePointer < fileLength) {
                    line = line + 1;
                }
            } else if( readByte == 0xD ) {
                if (filePointer < fileLength-1) {
                    line = line + 1;
                }
            }
            if (line >= lines) {
                break;
            }
            sb.append( ( char ) readByte );
        }

        String lastLine = sb.reverse().toString();
        return lastLine;
    } catch( java.io.FileNotFoundException e ) {
        e.printStackTrace();
        return null;
    } catch( java.io.IOException e ) {
        e.printStackTrace();
        return null;
    }
    finally {
        if (fileHandler != null )
            try {
                fileHandler.close();
            } catch (IOException e) {
            }
    }
}

像这样调用上面的方法:

File file = new File("D:\\stuff\\huge.log");
System.out.println(tail(file));
System.out.println(tail2(file, 10));

警告 在unicode的狂野西部,此代码可能导致此函数的输出错误.例如"Mary?s"而不是"Mary's".带有帽子,重音符号,汉字等的字符可能会导致输出错误,因为重音符号会在字符后添加为修饰符.反转复合字符会改变反转时字符身份的性质.您必须对计划使用此语言的所有语言进行全面的测试.

有关此unicode反转问题的更多信息,请阅读:http: //msmvps.com/blogs/jon_skeet/archive/2009/11/02/omg-ponies-aka-humanity-epic-fail.aspx


以上内容未考虑CR和LF终止的行.

2> jaco0646..:

Apache Commons有一个使用RandomAccessFile的实现.

它叫做ReversedLinesFileReader.


@JuanToroMarty可以遍历`readLine()`方法.

3> Jon Skeet..:

看看我对C#的类似问题的答案.虽然Java中的编码支持有些不同,但代码非常相似.

基本上,一般来说,这不是一件非常容易的事情.正如MSalter指出的那样,UTF-8确实很容易发现,\r或者\n因为这些字符的UTF-8表示与ASCII相同,并且这些字节不会以多字节字符出现.

所以基本上,取一个(比方说)2K的缓冲区,然后逐步向后读(在你之前跳到2K,读下一个2K)检查线路终止.然后跳到流中正确的位置,InputStreamReader在顶部创建一个,在顶部创建一个BufferedReader.然后打电话BufferedReader.readLine().


UTF-8并不重要 - 您需要最后一个CR或LF字符,它是ASCII和UTF-8中的单个字节.
推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有