大きなファイル (たとえば 2GB) から最後の n 行を読み取る必要があります。ファイルは UTF-8 でエンコードされています。
一番効率の良い方法を知りたいです。java の RandomAccessFile について読んでください。ただし、 seek() メソッドを実行し、メモリ内のファイル全体を読み取ります。ネイティブ実装を使用しているため、ソースコードを参照できませんでした。
大きなファイル (たとえば 2GB) から最後の n 行を読み取る必要があります。ファイルは UTF-8 でエンコードされています。
一番効率の良い方法を知りたいです。java の RandomAccessFile について読んでください。ただし、 seek() メソッドを実行し、メモリ内のファイル全体を読み取ります。ネイティブ実装を使用しているため、ソースコードを参照できませんでした。
RandomAccessFile.seek は、ファイル ポインターの現在の位置を設定するだけで、バイトはメモリに読み込まれません。
ファイルは UTF-8 でエンコードされているため、テキスト ファイルです。テキスト ファイルの読み取りには、通常 BufferedReader を使用します。Java 7 では、ファイルからテキストを読み取るための BufferedReader のインスタンスを作成する便利なメソッド File.newBufferedReader も追加されました。最後の 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 に達すると、バイトを反転して行を作成します。
次の 2 点を改善する必要があります。
バッファリング
EOLの認識
Random Access が必要な場合は、RandomAccessFile が必要です。何をしているのかわかっている場合は、これから取得したバイトを UTF-8 に変換できます。
BuffredReader を使用する場合、skip(n) を文字数で使用できます。つまり、ファイル全体を読み取る必要があります。
これを組み合わせて行う方法。FileInputStream を skip() で使用し、N 個の改行を読み戻して読み取り元を見つけ、ストリームを BufferedReader でラップして、UTF-8 エンコーディングで行を読み取ります。