21

RandomAccessFile は、ファイルへのランダム アクセスでは非常に低速です。その上にバッファリングされたレイヤーを実装することについてよく読んでいますが、これを行うコードはオンラインで見つけることができません。

私の質問は、このクラスのオープンソース実装を知っている皆さんは、ポインタを共有したり、独自の実装を共有したりできますか?

この質問が、この問題に関する有用なリンクとコードのコレクションとして判明するとよいでしょう。これは、多くの人が共有し、SUN によって適切に対処されることはないと確信しています。

ファイルは Integer.MAX_VALUE よりも大きくなる可能性があるため、MemoryMapping を参照しないでください。

4

6 に答える 6

13

次のようなコードを使用して、RandomAccessFile から BufferedInputStream を作成できます。

 RandomAccessFile raf = ...
 FileInputStream fis = new FileInputStream(raf.getFD());
 BufferedInputStream bis = new BufferedInputStream(fis);

注意事項

  1. FileInputStream を閉じると RandomAccessFile が閉じられ、その逆も同様です。
  2. RandomAccessFile と FileInputStream は同じ位置を指しているため、FileInputStream から読み取ると RandomAccessFile のファイル ポインターが進み、その逆も同様です。

おそらく、これを使用したい方法は次のようになります。

RandomAccessFile raf = ...
FileInputStream fis = new FileInputStream(raf.getFD());
BufferedInputStream bis = new BufferedInputStream(fis);

//do some reads with buffer
bis.read(...);
bis.read(...);

//seek to a a different section of the file, so discard the previous buffer
raf.seek(...);
bis = new BufferedInputStream(fis);
bis.read(...);
bis.read(...);
于 2013-12-14T06:07:13.507 に答える
12

ファイルが Integer.MAX_VALUE より大きい場合でも、java.nio.MappedByteBuffer を使用しない理由はわかりません。

明らかに、ファイル全体に対して単一の MappedByteBuffer を定義することは許可されません。ただし、ファイルの異なる領域にアクセスする複数の MappedByteBuffers を持つことができます。

FileChannel.map の位置とサイズの定義は long 型です。これは、Integer.MAX_VALUE を超える値を指定できることを意味します。注意しなければならないことは、バッファーのサイズがInteger.MAX_VALUE より大きくならないようにすることだけです。 .

したがって、次のようにいくつかのマップを定義できます。

buffer[0] = fileChannel.map(FileChannel.MapMode.READ_WRITE,0,2147483647L);
buffer[1] = fileChannel.map(FileChannel.MapMode.READ_WRITE,2147483647L, Integer.MAX_VALUE);
buffer[2] = fileChannel.map(FileChannel.MapMode.READ_WRITE, 4294967294L, Integer.MAX_VALUE);
...

要約すると、サイズを Integer.MAX_VALUE より大きくすることはできませんが、開始位置はファイル内のどこにでも置くことができます。

Book Java NIOで、著者の Ron Hitchens は次のように述べています。

メモリ マッピング メカニズムを介してファイルにアクセスすると、チャネルを使用している場合でも、従来の方法でデータを読み書きするよりもはるかに効率的です。時間のかかる明示的なシステム コールを行う必要はありません。さらに重要なことは、オペレーティング システムの仮想メモリ システムがメモリ ページを自動的にキャッシュすることです。これらのページはシステム メモリを使用してキャッシュされ、JVM のメモリ ヒープのスペースを消費しません。

メモリ ページが有効になると (ディスクから取り込まれると)、データを取得するために別のシステム コールを行う必要なく、フル ハードウェア スピードで再度アクセスできます。頻繁に参照または更新されるインデックスまたはその他のセクションを含む大規模な構造化ファイルは、メモリ マッピングから大きなメリットを得ることができます。クリティカル セクションを保護し、トランザクションの原子性を制御するためにファイル ロックと組み合わせると、メモリ マップト バッファを有効に活用できることがわかります。

サードパーティの API がそれよりも優れた機能を提供しているとは思えません。おそらく、作業を簡素化するために、このアーキテクチャの上に書かれた API を見つけるかもしれません。

このアプローチはあなたのために働くべきだと思いませんか?

于 2011-04-11T15:29:12.553 に答える
2

RandomAccessFileは、ファイルへのランダムアクセスには非常に時間がかかります。バッファリングされたレイヤーをその上に実装することについてよく読んでいますが、これを行うコードをオンラインで見つけることはできません。

さて、オンラインで見つけることは可能です。
1つは、jpeg2000のJAIソースコードに実装があり、さらに邪魔にならないimplが http://www.unidata.ucar.edu/software/netcdf-java/にあります。

javadocs:

http://www.unidata.ucar.edu/software/thredds/v4.3/netcdf-java/v4.0/javadoc/ucar/unidata/io/RandomAccessFile.html

于 2012-01-23T23:40:30.020 に答える
1

64 ビット マシンで実行している場合は、メモリ マップト ファイルが最適な方法です。ファイル全体を同じサイズのバッファーの配列にマップし、必要に応じて各レコードのバッファーを選択するだけです (つまり、edalorzoの答えですが、境界にまたがるレコードがないように、オーバーラップ バッファーが必要です)。

32 ビット JVM で実行している場合は、RandomAccessFile. ただし、これを使用してbyte[]レコード全体を含む を読み取り、次に a を使用ByteBufferしてその配列から個々の値を取得できます。最悪の場合、2 つのファイル アクセスを行う必要があります。1 つはレコードの位置/サイズを取得するため、もう 1 つはレコード自体を取得するためです。

ただし、大量の を作成すると、ガベージ コレクターに負荷がかかり始める可能性があることに注意してくださいbyte[]。また、ファイル全体をバウンスすると、IO バウンドのままになることに注意してください。

于 2011-04-11T16:04:52.497 に答える
1

Apache PDFBox プロジェクトには、優れたテスト済みBufferedRandomAccessFileのクラスがあります。
Apache ライセンス、バージョン 2.0 の下でライセンス供与

JavaWorld.comで Nick Zhang が説明しているように、これはjava.io.RandomAccessFileクラスの最適化されたバージョンです。jmzreader実装に基づいており、符号なしバイトを処理するように拡張されています。

ここのソースコードを参照してください:

  1. https://github.com/apache/pdfbox/.../fontbox/ttf/BufferedRandomAccessFile.java
  2. https://svn.apache.org/repos/asf/pdfbox/.../fontbox/ttf/BufferedRandomAccessFile.java
于 2021-03-30T15:25:52.043 に答える