2013-03-25 12 views
11

大きなファイル(たとえば2GB)から最後のn行を読み込む必要があります。このファイルはUTF-8でエンコードされています。JavaのRandomAccessFileはメモリ内のファイル全体を読み込みますか?

これを行う最も効率的な方法を知りたいですか? javaのRandomAccessFileについて読むが、seek()メソッドはメモリ内のファイル全体を読み込む。ネイティブ実装を使用しているため、ソースコードを参照できませんでした。

+0

いいえ、 'seek()'はファイル全体はもちろんのこと、* anything *をメモリに読み込まない。あなたは完全なコントロールを持っています。 – NPE

+0

私はその質問を読んだが、ファイルがUTF-8でエンコードされている場合は、RandomAccessFileの使用が落胆していると理解したいと思いますか? –

+1

重複に同意しない。これはRandomAccessFileに重点を置いていますが、もう1つはアプリケーションに関するもので、RAFについては言及していません。 –

答えて

6

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

2)あなたのファイルはUTF-8でエンコードされているため、テキストファイルです。私たちが通常BufferedReaderを使用するテキストファイルを読むために、Java 7はFile.newBufferedReaderという便利なメソッドを追加してファイルからテキストを読み込むBufferedReaderのインスタンスを作成しました。最後の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); 
} 

基本的な例です。これは、LFに達すると、それはバイトを逆にしてラインを作成し、尾からByteArrayOutputStreamに開始バイトの後のファイルのバイトを読み込みます。

2つのことを改善する必要があります:1)バッファリング2)EOL認識

+1

ファイル全体を読み取らずにBufferedReaderを使用する方法を含めることはできますか? –

+0

行ごとに読み込むので、ファイル全体をメモリに読み込んでいません –

+0

最初から行ごとに読み込んでいるので、ファイル全体が読み込まれていても全体を読み込んでいます一度にファイル。 –

0

あなたはランダムアクセスが必要な場合は、あなたがたRandomAccessFileを必要としています。あなたが何をしているか知っていれば、これから得たバイトをUTF-8に変換することができます。

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


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

+0

これはつまり、終わり、私はファイル全体を読むことになりますメモリに? –

+0

もしあなたが私のようにしていないならば。 BufferedReaderを単独で使用すると、ファイル全体が読み取られますが、これは私があなたがそれを行うことを示唆していません。 –

+0

あなたはこの初心者のためのスニペットコードを共有できますか?(ファイルの終わりに到達し、n行にトレースしてから、n行をメモリに読み込みます。 –

関連する問題