快速读取文本文件的最后一行?
在Java中,从[非常非常大]文件中读取最后一行文本的最快,最有效的方法是什么?
下面是两个函数,一个返回文件的最后一个非空行而不加载或单步执行整个文件,另一个返回文件的最后 N 行而不单步执行整个文件:
tail 的作用是直接缩放到文件的最后一个字符,然后逐个字符地向后退一步,记录它所看到的内容,直到找到换行符。一旦它找到换行符,它就会中断循环。反转录制的内容并将其放入字符串中并返回。0xA是新行,0xD是回车符。
如果您的行尾是或或其他一些“双换行符样式换行符”,那么您必须指定n * 2行才能获得最后n行,因为它每行计数2行。\r\n
crlf
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 的狂野西部,此代码可能导致此函数的输出出错。例如,“玛丽的”而不是“玛丽的”。带有帽子,重音符号,中文字符等的字符可能会导致输出错误,因为重音符号是作为修饰符添加到字符之后的。反转复合字符会在反转时更改字符身份的性质。您将不得不对您计划使用它的所有语言进行全面的测试。
有关此 Unicode 反转问题的更多信息,请阅读以下内容:https://codeblog.jonskeet.uk/2009/11/02/omg-ponies-aka-humanity-epic-fail/