2011-01-06 101 views
3

私のプログラムは、ランダムアクセスで巨大なバイナリファイルからチャンクを読み込む必要があります。私は数千のエントリを持つオフセットと長さのリストを持っています。ユーザはエントリを選択し、プログラムはオフセットを求めて、lengthバイトを読み込みます。Delphiで巨大なファイルを読み込む最速の方法は何ですか?

プログラムは内部的にTMemoryStreamを使用して、ファイルから読み込んだチャンクを保存して処理します。データの読み取りは、次のようにTFileStreamを介して行われます。これは正常に動作しますが、ファイルが大きくなるにつれて、残念ながら、それはますます遅くなり

FileStream.Position := Offset; 
MemoryStream.CopyFrom(FileStream, Size); 

。ファイルサイズは数メガバイトから始まりますが、頻繁に数十ギガバイトに達します。読み込まれるチャンクは、およそ100キロバイトです。

ファイルの内容は、自分のプログラムでのみ読み取られます。これは、その時点でファイルにアクセスしている唯一のプログラムです。また、ファイルはローカルに保存されるため、ネットワーク上の問題ではありません。

私はDelphi 2007をWindows XPのボックスで使用しています。

このファイルへのアクセスを高速化するにはどうすればよいですか?

編集:

  • ファイルアクセスに関係なく、ファイルの一部を読まされているの、大きなファイルの遅いです。
  • 通常、プログラムはファイルを順番に読み込みません。チャンクの順序はユーザー主導であり、予測することはできません。
  • 小さなファイルから同じ大きさのチャンクを読み取るよりも、大きなファイルからチャンクを読み取るのは、常に遅くなります。
  • 私は、ファイル全体を処理するのにかかる全体的な時間ではなく、ファイルからチャンクを読み取るためのパフォーマンスについて話しています。後者は大きなファイルの方が明らかに時間がかかりますが、ここで問題にはなりません。

私はみんなに謝罪する必要があります:それは違いの多くをしなかったことが判明示唆したように、私は、メモリマップドファイルを使用してファイルアクセスを実現した後。しかし、それはプログラムを遅くするファイルアクセスではないという、より多くのタイミングコードを追加した後にも判明しました。ファイルアクセスは、ファイルサイズに関係なく、ほぼ一定の時間がかかります。私がまだ特定していないユーザーインターフェイスの一部は、大量のデータでパフォーマンスに問題があるようですが、何とか最初にプロセスのタイミングをとったときに何らかの違いが見られませんでした。

ボトルネックを特定するのは申し訳ありません。

+1

明らかなことはありません。これらのストリームクラスは、システムファイルI/O関数のまわりのラッパーです。あなたはどのようにランダムアクセスパターンのものを大幅に改善できますか? –

+0

あなたは単一のシーク/リードがユーザにとって著しく遅いと言っていますか?あるいは、これらの操作の大規模な「バッチ」が遅いのでしょうか?ディスクからデータが来ている場合は、ファイルのサイズに関係なく、シークとリードの操作はほぼ同じになります。 7200 rpmディスクでは、5〜10 msの間であるべきです。 –

+0

メモリの断片化の問題が考えられます。操作間でTMemoryStreamを解放していますか?アプリケーションの寿命の間、それを生かしておき、減速が消えるかどうか確認してください。 –

答えて

3

CreateFile()WinAPI関数のヘルプトピックを開くと、FILE_FLAG_NO_BUFFERINGやFILE_FLAG_RANDOM_ACCESSなどの興味深いフラグがあります。あなたは彼らと一緒に演奏していくらかのパフォーマンスを得ることができます。

次に、サイズが100KBであってもファイルデータをコピーすることは、処理を遅くする余分なステップです。 CreateFileMappingとMapViewOfFile関数を使用して、すぐに使用できるデータへのポインタを取得することをお勧めします。この方法では、コピーを避け、特定のパフォーマンス上の利点を得ることもできます(スピードを慎重に測定する必要があります)。以下に、その後

並び替え最大fileposition上のエントリと::

+0

データのコピーはファイルサイズに関係なく行われるため、ボトルネックにはなりません。 – dummzeuch

+0

@dummzeuch誰が言ったのですか?マップされたメモリへのポインタを取得します。そのようにコピーする必要はなく、マップされたメモリに直接アクセスできます。 MMFは1つの読書を保存する(少なくとも) –

+0

合意。 MMFは普通のファイルI/Oを使用するほうがはるかに高速です。私のプロジェクトの1つでは、最大数GBのバイナリログファイルを開く必要があります。ランダムなファイルI/Oを使用してこのようなファイルを検索するには数分かかることがありますが、MMFで同じ作業を行うのは時間のほんの一部です。 –

0

たぶん、あなたは、このアプローチを取ることができ

  1. は、特定までのファイルの最初のX MBを(必要なエントリを取りますすべてのためのfileposition)バッファにファイルから
  2. 読むX MB(TMemorystream
  3. 今多分マルチスレッド(バッファからエントリを読んで)
  4. を繰り返し、このエントリ。要するに

:ファイルの一部をキャッシュし、それ(multhithreaded)に収まるすべてのエントリを読んで、その後、次の部分をキャッシュあなたは自分の独創的なアプローチを取る場合など

はたぶん、あなたはスピードを得ることができますただし、位置のエントリをソートします。

+0

ファイルが順番に読み込まれないために役立たないでしょう。 – dummzeuch

0

Delphiの在庫TMemoryStreamはメモリの割り当て方法が遅いため、遅いです。 NexusDB社には、はるかに効率的なTnxMemoryStreamがあります。そこには、より良い仕事をするいくつかの無料のものがあるかもしれません。

株Delphi TFileStreamも最も効率的なコンポーネントではありません。歴史の中での歩みJulian Bucknallは、ファイルストリームを非常に効率的に扱う、雑誌やどこかにBufferedFileStreamという名前のコンポーネントを公開しました。

幸運。

関連する問題