12

新しいファイル ハンドルを作成して、そのハンドルへの書き込み操作がすぐにディスクに書き込まれるようにする必要があります。

追加情報: ハンドルは子プロセスの継承された STDOUT になるため、そのプロセスからの出力をすぐにディスクに書き込む必要があります。

ドキュメントを調べるCreateFileと、FILE_FLAG_WRITE_THROUGHフラグは私が必要としているものとまったく同じように見えました:

書き込み操作は中間キャッシュを経由せず、ディスクに直接送信されます。

非常に基本的なテスト プログラムを作成しましたが、うまくいきません。CreateFile でフラグを使用WriteFile(myHandle,...)してから、長いループで使用し、約 15 秒で約 100 MB のデータを書き込みました。(私はいくつかのを追加しましたSleep())。

次に、エクスプローラーで「F5」を連続して押すことからなる専門的な監視環境をセットアップしました。結果: ファイルは 0kB のままで、テスト プログラムが終了する頃に 100MB にジャンプします。

次に試したのは、書き込みごとに手動でファイルをフラッシュすることでしたFlushFileBuffers(myHandle)。これにより、観測されたファイル サイズが期待どおりに安定して増加します。

私の質問は、ファイルを手動でフラッシュせずにFILE_FLAG_WRITE_THROUGHこれを行うべきではなかったのでしょうか? 何か不足していますか?「実際の」プログラムでは、ファイルをフラッシュできません。これは、ファイルを使用している子プロセスを制御できないためです。

FILE_FLAG_NO_BUFFERING同じ理由で使用できないというフラグもあります。ハンドルを使用しているプロセスを制御できないため、このフラグで必要な書き込みを手動で調整することはできません。

編集:ファイルのサイズがどのように変化するかを監視するための別のプロジェクトを作成しました。.NETFileSystemWatcherクラスを使用します。また、書き込むデータも少なくなり、合計で約 100kB になります。

これが出力です。タイムスタンプの秒を確認してください。

「組み込みのバッファなし」バージョン:

25.11.2008 7:03:22 PM: 10230 bytes added.
25.11.2008 7:03:31 PM: 10240 bytes added.
25.11.2008 7:03:31 PM: 10240 bytes added.
25.11.2008 7:03:31 PM: 10240 bytes added.
25.11.2008 7:03:31 PM: 10200 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10190 bytes added.

...そして「強制(手動)フラッシュ」バージョン(FlushFileBuffers()〜2.5秒ごとに呼び出されます):

25.11.2008 7:06:10 PM: 10230 bytes added.
25.11.2008 7:06:12 PM: 10230 bytes added.
25.11.2008 7:06:15 PM: 10230 bytes added.
25.11.2008 7:06:17 PM: 10230 bytes added.
25.11.2008 7:06:19 PM: 10230 bytes added.
25.11.2008 7:06:21 PM: 10230 bytes added.
25.11.2008 7:06:23 PM: 10230 bytes added.
25.11.2008 7:06:25 PM: 10230 bytes added.
25.11.2008 7:06:27 PM: 10230 bytes added.
25.11.2008 7:06:29 PM: 10230 bytes added.
4

5 に答える 5

12

私も、クラッシュ ログのコンテキストで、これに悩まされてきました。

FILE_FLAG_WRITE_THROUGH送信するデータが返される前にファイルシステムに送信されることのみを保証します。WriteFile実際に物理デバイスに送信されることは保証されません。したがって、たとえば、このフラグを使用してハンドルで a のReadFile後に aを実行するWriteFileと、ファイルシステム キャッシュからデータを取得したか、基盤となるデバイスからデータを取得したかに関係なく、書き込み済みのバイトが返されることが保証されます。

データがデバイスに書き込まれたことを保証したい場合は、それFILE_FLAG_NO_BUFFERINGに付随するすべての追加作業が必要です。これらの書き込みは、たとえば、バッファが戻る前にデバイス ドライバに到達するため、位置合わせする必要があります。

ナレッジ ベースには、この違いに関する簡潔ですが有益な記事があります。

あなたの場合、親プロセスが子よりも長生きする場合は、次のことができます。

  1. API を使用CreatePipeして、継承可能な匿名パイプを作成します。
  2. CreateFileセットでファイルを作成するために使用しますFILE_FLAG_NO_BUFFERING
  3. パイプの書き込み可能なハンドルをその STDOUT として子に提供します。
  4. 親プロセスで、パイプの読み取り可能なハンドルから整列されたバッファーに読み取り、それらをファイルに書き込みます。
于 2008-11-25T17:27:52.730 に答える
5

これは古い質問ですが、少し追加できると思いました。実際、ここにいる全員が間違っていると私は信じています。write-through と unbuffered-io を使用してストリームに書き込む場合、ディスクには書き込みますが、ファイル システムに関連付けられたメタデータは更新しません (たとえば、エクスプローラーが表示するもの)。

ここで、この種のものに関する良いリファレンスを見つけることができますhttp://winntfs.com/2012/11/29/windows-write-caching-part-2-an-overview-for-application-developers/

乾杯、

グレッグ

于 2013-07-24T15:38:29.340 に答える
2

おそらく、あなたは十分に満足できるでしょうFlushFileBuffers

指定されたファイルのバッファーをフラッシュし、バッファー内のすべてのデータをファイルに書き込みます。

通常、WriteFileおよびWriteFileEx関数は、オペレーティング システムがディスクまたは通信パイプに定期的に書き込む内部バッファにデータを書き込みます。FlushFileBuffers関数は、指定されたファイルのバッファリングされたすべての情報をデバイスまたはパイプに書き込みます。

彼らは、バッファを大量にフラッシュするためにflushを呼び出すことは非効率的であると警告しています-そして、キャッシングを無効にする方が良いです(つまり、ティムの答え):

システム内のディスク キャッシングの相互作用により、FlushFileBuffers関数は、多くの書き込みが個別に実行されているときに、ディスク ドライブ デバイスへの書き込みのたびに使用すると非効率になる可能性があります。アプリケーションがディスクへの複数の書き込みを実行しており、重要なデータが永続メディアに確実に書き込まれるようにする必要がある場合、アプリケーションはFlushFileBuffersを頻繁に呼び出すのではなく、バッファリングされていない I/O を使用する必要があります。バッファリングされていない I/O 用にファイルを開くには、フラグとフラグを指定してCreateFile関数を呼び出します。これにより、ファイルの内容がキャッシュされなくなり、書き込みごとにメタデータがディスクにフラッシュされます。詳細については、CreateFileを参照してください。FILE_FLAG_NO_BUFFERINGFILE_FLAG_WRITE_THROUGH

パフォーマンスが高くなく、頻繁にフラッシュしない場合は、FlushFileBuffers で十分 (かつ簡単) かもしれません。

于 2010-03-03T20:09:13.907 に答える
2

エクスプローラーで表示しているサイズは、ファイル システムが認識しているファイルのサイズと完全には同期していない可能性があるため、これは最適な測定方法ではありません。FlushFileBuffers によってファイル システムが Explorer が見ている情報を更新することがあります。それを閉じて再度開くと、同じことが起こる可能性があります。

他の人が言及したディスクキャッシングの問題は別として、ライトスルーはあなたが望んでいたことをしています。ディレクトリで「dir」を実行しても、最新の情報が表示されない場合があるだけです。

ライトスルーが「ファイルシステムに」のみ書き込むことを示唆する回答は、まったく正しくありません。ファイル システム キャッシュに書き込みますが、データをディスクに送信します。ライトスルーは、後続の読み取りがキャッシュから満たされることを意味する場合がありますが、ステップをスキップしてディスクに書き込んでいないことを意味するわけではありません。記事の要約をよく読んでください。これは、ほぼすべての人にとって混乱を招くビットです。

于 2010-08-27T20:28:34.407 に答える