6

私は本当に困っています:FileChannelsとsを使用して数GBを超える巨大なファイルを読みたい-私が見つけたすべてのドキュメントは、メソッドMappedByteBufferを使用してファイルをマップするのはかなり簡単であることを示唆しています。FileChannel.map()もちろん、すべてのBufferメソッドが位置、制限、および容量にintを使用するため、2GBに制限がありますが、それより下のシステムの暗黙の制限についてはどうでしょうか。

実際には、私はOutOfMemoryExceptionsに関して多くの問題を抱えています!そして、実際に限界を定義する文書はまったくありません!では、int-limitに収まるファイルを、MappedByteBuffer例外を取得せずに1つまたは複数のsに安全にマップするにはどうすればよいですか?

試す前に、ファイルのどの部分を安全にマップできるかをシステムに尋ねることはできますFileChannel.map()か?どのように?この機能に関するドキュメントが非常に少ないのはなぜですか?

4

4 に答える 4

9

いくつかの実用的なコードを提供できます。これで問題が解決するかどうかはわかりません。これは、によって認識されるパターンのファイルを探しますHunter

優れた記事「 Javaのヒント:元の調査のためにファイルをすばやく読み取る方法(私のものではない)」を参照してください。

// 4k buffer size.
static final int SIZE = 4 * 1024;
static byte[] buffer = new byte[SIZE];

// Fastest because a FileInputStream has an associated channel.
private static void ScanDataFile(Hunter p, FileInputStream f) throws FileNotFoundException, IOException {
  // Use a mapped and buffered stream for best speed.
  // See: http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly
  FileChannel ch = f.getChannel();
  long red = 0L;
  do {
    long read = Math.min(Integer.MAX_VALUE, ch.size() - red);
    MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, red, read);
    int nGet;
    while (mb.hasRemaining() && p.ok()) {
      nGet = Math.min(mb.remaining(), SIZE);
      mb.get(buffer, 0, nGet);
      for (int i = 0; i < nGet && p.ok(); i++) {
        p.check(buffer[i]);
      }
    }
    red += read;
  } while (red < ch.size() && p.ok());
  // Finish off.
  p.close();
  ch.close();
  f.close();
}
于 2012-09-21T14:05:36.450 に答える
7

私が使用しているのはList<ByteBuffer>、各ByteBufferが16MBから1GBのブロックでファイルにマップされる場所です。ロジックを単純化するために2の累乗を使用します。これを使用して、最大8TBのファイルをマップしました。

メモリマップトファイルの主な制限は、仮想メモリによって制限されることです。32ビットJVMを使用している場合は、あまりマッピングできません。

ファイルの新しいメモリマッピングはクリーンアップされないため、作成し続けることはありません。これらはたくさん作成できますが、一部のシステムでは約32Kの制限があるようです(どれほど小さくても)

MemoryMappedFilesが便利だと思う主な理由は、フラッシュする必要がないことです(OSが停止しないと想定できる場合)。これにより、データが失われることを心配せずに、低レイテンシでデータを書き込むことができます。 write()またはflush()を実行する必要があるため、アプリケーションが停止するか、パフォーマンスが高すぎます。

于 2012-09-21T14:38:07.090 に答える
3

FileChannelAPIを使用してファイル全体を一度に書き込むことはありません。代わりに、ファイルを分割して送信します。JavaIO技術のパフォーマンスを比較するMartinThompsonの投稿のサンプルコードを参照してください:Java Sequential IO Performance

さらに、プラットフォームに依存する呼び出しを行っているため、ドキュメントはあまりありません。map()JavaDocから:

メモリマップトファイルの詳細の多くは、本質的に基盤となるオペレーティングシステムに依存しているため、指定されていません。

于 2012-09-21T14:04:12.237 に答える
2

ファイルが大きいほど、一度にすべてのファイルをメモリに保存する必要は少なくなります。ファイルを一度にバッファ、一度に1行などを処理する方法を考案します。

マップされたメモリのリリースが定義されていないため、MappedByteBuffersは特に問題があります。したがって、一度に複数を使用すると、基本的に失敗します。

于 2012-09-21T21:54:50.520 に答える