Ответ 1
-
RandomAccessFile.seek просто устанавливает текущую позицию указателя файла, никакие байты не считываются в память.
-
Так как ваш файл кодируется в кодировке UTF-8, это текстовый файл. Для чтения текстовых файлов мы обычно используем BufferedReader, Java 7 даже добавил метод удобства File.newBufferedReader для создания экземпляра BufferedReader для чтения текста из файла. Хотя это может быть неэффективно для чтения последних n строк, но их легко реализовать.
-
Чтобы быть эффективными, нам нужен RandomAccessFile и читать файл назад, начиная с конца. Вот базовый пример
public static void main(String[] args) throws Exception {
int n = 3;
List<String> lines = new ArrayList<>();
try (RandomAccessFile f = new RandomAccessFile("test", "r")) {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
for (long length = f.length(), p = length - 1; p > 0 && lines.size() < n; p--) {
f.seek(p);
int b = f.read();
if (b == 10) {
if (p < length - 1) {
lines.add(0, getLine(bout));
bout.reset();
}
} else if (b != 13) {
bout.write(b);
}
}
}
System.out.println(lines);
}
static String getLine(ByteArrayOutputStream bout) {
byte[] a = bout.toByteArray();
// reverse bytes
for (int i = 0, j = a.length - 1; j > i; i++, j--) {
byte tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
return new String(a);
}
Он читает байт файла после байта, начиная с хвоста до ByteArrayOutputStream, когда достигается LF, он меняет байты и создает строку.
Необходимо улучшить две вещи:
-
буферизация
-
Распознавание EOL