使用 RandomAccessFile,并尝试读取更大的缓冲区。我用tail
line-length-hint 做了一个函数,来做个猜测。请注意,文件是否以换行符结尾或可能会对结果产生影响。也可以改进代码(两个块大小的幂等)。
File textFile = new File("...");
String[] lines = tail(textFile, "UTF-8", 10, 160);
System.out.println("#Lines: " + lines.length);
for (String line : lines) {
System.out.println(line);
}
String[] tail(File textFile, String charSet, int lines, int lineLengthHint)
throws IOException {
if (lineLengthHint < 80) {
lineLengthHint = 80;
}
RandomAccessFile in = new RandomAccessFile(textFile, "r");
try {
long fileSize = in.length();
int bytesCount = lines * lineLengthHint;
// Loop allocating a byte array hopefully sufficiently large.
for (;;) {
if (fileSize < bytesCount) {
bytesCount = (int)fileSize;
}
byte[] bytes = new byte[bytesCount];
in.seek(fileSize - bytesCount);
in.readFully(bytes);
int startIndex = bytes.length; // Position of last '\n'.
int lineEndsFromStart = 0;
boolean bytesCountSufficient = true;
while (lineEndsFromStart - 1 < lines) {
int pos = startIndex - 1;
while (pos >= 0 && bytes[pos] != '\n') {
--pos;
}
startIndex = pos; // -1 will do fine.
++lineEndsFromStart;
if (pos < 0) {
bytesCountSufficient = false;
break;
}
}
if (bytesCountSufficient || fileSize == bytesCount) {
String text = new String(bytes, startIndex + 1,
bytes.length - (startIndex + 1), charSet);
return text.split("\r?\n");
}
// Not bytesCountSufficient:
//lineLengthHint += 10; // Average line length was larger.
bytesCount += lineLengthHint * 4; // Try with more.
}
} finally {
in.close();
}
}