Eri*_*ski 85
下面是两个函数,一个返回文件的最后一个非空行而不加载或单步执行整个文件,另一个返回文件的最后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 */
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是你可能不想要最后一行,你想要最后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) {
}
}
}
Run Code Online (Sandbox Code Playgroud)
像这样调用上面的方法:
File file = new File("D:\\stuff\\huge.log");
System.out.println(tail(file));
System.out.println(tail2(file, 10));
Run Code Online (Sandbox Code Playgroud)
警告 在unicode的狂野西部,此代码可能导致此函数的输出错误.例如"Mary?s"而不是"Mary's".带有帽子,重音符号,汉字等的字符可能会导致输出错误,因为重音符号会在字符后添加为修饰符.反转复合字符会改变反转时字符身份的性质.您必须对计划使用此语言的所有语言进行全面的测试.
有关此unicode反转问题的更多信息,请阅读:http: //msmvps.com/blogs/jon_skeet/archive/2009/11/02/omg-ponies-aka-humanity-epic-fail.aspx
Jon*_*eet 19
看看我对C#的类似问题的答案.虽然Java中的编码支持有些不同,但代码非常相似.
基本上,一般来说,这不是一件非常容易的事情.正如MSalter指出的那样,UTF-8确实很容易发现,\r或者\n因为这些字符的UTF-8表示与ASCII相同,并且这些字节不会以多字节字符出现.
所以基本上,取一个(比方说)2K的缓冲区,然后逐步向后读(在你之前跳到2K,读下一个2K)检查线路终止.然后跳到流中正确的位置,InputStreamReader在顶部创建一个,在顶部创建一个BufferedReader.然后打电话BufferedReader.readLine().
使用 FileReader 或 FileInputStream 将不起作用 - 您必须使用FileChannel或RandomAccessFile从末尾向后循环遍历文件。正如乔恩所说,编码将是一个问题。
| 归档时间: |
|
| 查看次数: |
86309 次 |
| 最近记录: |