11

大きなファイル (たとえば 2GB) から最後の n 行を読み取る必要があります。ファイルは UTF-8 でエンコードされています。

一番効率の良い方法を知りたいです。java の RandomAccessFile について読んでください。ただし、 seek() メソッドを実行し、メモリ内のファイル全体を読み取ります。ネイティブ実装を使用しているため、ソースコードを参照できませんでした。

4

2 に答える 2

6
  1. RandomAccessFile.seek は、ファイル ポインターの現在の位置を設定するだけで、バイトはメモリに読み込まれません。

  2. ファイルは UTF-8 でエンコードされているため、テキスト ファイルです。テキスト ファイルの読み取りには、通常 BufferedReader を使用します。Java 7 では、ファイルからテキストを読み取るための BufferedReader のインスタンスを作成する便利なメソッド File.newBufferedReader も追加されました。最後の n 行を読むには効率が悪いかもしれませんが、実装は簡単です。

  3. 効率的にするには、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 点を改善する必要があります。

  1. バッファリング

  2. EOLの認識

于 2013-03-25T10:30:13.570 に答える
0

Random Access が必要な場合は、RandomAccessFile が必要です。何をしているのかわかっている場合は、これから取得したバイトを UTF-8 に変換できます。

BuffredReader を使用する場合、skip(n) を文字数で使用できます。つまり、ファイル全体を読み取る必要があります。


これを組み合わせて行う方法。FileInputStream を skip() で使用し、N 個の改行を読み戻して読み取り元を見つけ、ストリームを BufferedReader でラップして、UTF-8 エンコーディングで行を読み取ります。

于 2013-03-25T10:34:46.967 に答える