メモリマップファイルはオプションで書き込み可能ですか?
-
06-07-2019 - |
質問
メモリマップファイルを使用する場合、読み取り専用または書き込み専用のいずれかであるようです。つまり、次のことはできません:
- 書き込み用に開いて、後で保存しないことを決定
- 読み取り用に開いたままにして、後で保存することにしました
アプリケーションは、書き込み可能なメモリマップファイルを使用してデータファイルを保存しますが、ユーザーが変更を保存せずに終了する場合があるため、ユーザーが実際に編集する一時ファイルを使用する必要があります。ユーザーが変更を保存することを選択すると、元のファイルは一時ファイルで上書きされるため、最新の変更が適用されます。これは、ファイルが非常に大きく(> 1GB)なる可能性があり、コピーに時間がかかるため、面倒です。
ファイルマッピングの作成に使用されるフラグの多くの組み合わせを試しましたが、オンデマンドで保存する柔軟性を可能にするものはありません。誰でもこれが事実であることを確認できますか?私たちのアプリケーションはDelphiで書かれていますが、標準のWindows APIを使用してマッピングを作成します。この例では
FMapHandle := CreateFileMapping(FFileHandle, nil, PAGE_READWRITE, 0, 2 * 65536, nil);
FBasePointer := MapViewOfFile(FileMapHandle, FILE_MAP_WRITE, FileOffsetHigh,
FileOffsetLow, NumBytes);
解決
できるとは思わない。つまり、あなたは できますが、私には意味がありません:-)
メモリマップファイルのポイントは、実際のファイルへのウィンドウであるということです。ファイルに反映された変更を行わない場合は、おそらくデータ構造(たとえば、ベースアドレス、サイズ、データの配列)の変更をまとめて保存するときに適用する必要があります。
この場合、実際にメモリマップファイルを必要せず、変更したいチャンクを読み込んで維持します(マルチユーザーアクセスの可能性がある場合は、最初にファイルをロックします)。
更新:
保存時に、元のファイルを削除し、一時ファイルの名前を元のファイル名に変更する可能性を考えましたか?これは、1Gのデータを一時データから元のデータにコピーするよりもはるかに高速です。そうすれば、保存したくない場合は、一時ファイルを削除して元のファイルを保持してください。
ロード時には元のデータを一時ファイルにコピーする必要がありますが、(保存するかどうかに関係なく)一時データをコピーして戻す必要はありません。これにより、所要時間が半分になります。
他のヒント
可能ですが、簡単ではありません。
メモリマップの基本と、メモリマップファイルの3つのモードの違いを理解する必要があります。両方とも仮想アドレス空間の一部を確保し、内部テーブルにマッピングエントリを作成します。最初は物理RAMは割り当てられていません。したがって、メモリにアクセスしようとすると、CPUに障害が発生し、OSを修正する必要があります。ファイルの内容をRAMにコピーし、RAMをプロセスのフォールトアドレスにマッピングします。
現在、3つのモードの違いは、マッピングされたページでの記述子の設定方法です。すべての場合において、ページの読み取りアクセス権を取得します。 (最初のモード)。ただし、書き込みアクセスを要求し、その後書き込みを行う場合、最初の書き込みでページは書き込み可能およびダーティとしてマークされます。その後、OSの裁量で、元のファイルに書き戻すことができます(第2モード)。最後に、コピーオンライトのセマンティクスを取得することが可能です。メモリ内のページへの読み取りアクセスのみで開始します。あなたがそれに書き込むとき、CPUはまだ故障しており、OSはそれを修正する必要があります。コピーオンライトでは、変更されたページのバッキングストアを元のマップファイルではなくページファイルに設定することにより、その修正が行われます。
したがって、あなたの場合、コピーオンライトモードを使用します。ユーザーが変更を破棄することを決定した場合、問題ありません。単にメモリマッピングを破棄します。メモリ内で変更され、ページファイルによってバックアップされたすべてのページも破棄されます。
ユーザーが保存することを決定した場合、少し難しいタスクがあります。ここで、ファイルのどの部分が変更されたかを把握する必要があります。これらの変更はメモリ内にあり、ソースファイルに再適用する必要があります。これを行うには、ページガードを使用します。したがって、ユーザーが保存することを決定したら、変更されたすべてのページを別のメモリブロックにコピーし、(変更されていない)ファイルを書き込み用に再マッピングし、変更を適用します。