7

少し背景:大きなファイルでIOを実行するときに、FILE_FLAG_NO_BUFFERINGフラグを使用して実験してきました。バックグラウンドIOを使用して、ユーザーマシンへのアプリの影響を減らすことを期待して、キャッシュマネージャーの負荷を軽減しようとしています。パフォーマンスは問題ではありません。可能な限り舞台裏にいることは大きな問題です。バッファリングされていないIOを実行するためのほぼ機能するラッパーがありますが、奇妙な問題が発生しました。4の倍数ではないオフセットを使用してReadを呼び出すと、このエラーが発生します。

Handleは同期操作をサポートしていません。FileStreamコンストラクターのパラメーターを変更して、ハンドルが非同期で開かれた(つまり、重複したI / Oのために明示的に開かれた)ことを示す必要がある場合があります。

なぜこれが起こるのですか?そして、このメッセージはそれ自体と矛盾していませんか?非同期ファイルオプションを追加すると、IOExceptionが発生します(パラメーターが正しくありません)。

本当の問題は、これらの要件( http://msdn.microsoft.com/en-us/library/windows/desktop/cc644950%28v=vs.85%29.aspx)がこれらの倍数と何の関係があるかということだと思います。 4.4。

この問題を示すコードは次のとおりです。

FileOptions FileFlagNoBuffering = (FileOptions)0x20000000;
int MinSectorSize = 512;
byte[] buffer = new byte[MinSectorSize * 2];
int i = 0;
while (i < MinSectorSize)
{
    try
    {
        using (FileStream fs = new FileStream(@"<some file>", FileMode.Open, FileAccess.Read, FileShare.None, 8, FileFlagNoBuffering | FileOptions.Asynchronous))
        {
            fs.Read(buffer, i, MinSectorSize);
            Console.WriteLine(i);
        }
    }
    catch { }
    i++;
}
Console.ReadLine();
4

2 に答える 2

12

を使用する場合FILE_FLAG_NO_BUFFERING、文書化された要件は、読み取りまたは書き込みのメモリアドレスが物理セクターサイズの倍数でなければならないことです。コードでは、バイト配列のアドレスをランダムに選択できるようにして(したがって、物理セクターサイズの倍数になる可能性は低い)、オフセットを追加します。

観察している動作は、オフセットが4の倍数である場合に呼び出しが機能することです。バイト配列が4バイト境界に整列している可能性が高いため、メモリアドレスが4の倍数である場合に呼び出しが機能します。 。

したがって、質問は次のように書き直すことができます。メモリアドレスが4の倍数であるのに、ドキュメントに512の倍数である必要があると記載されているのに、なぜ読み取りが機能するのでしょうか。

答えは、ルールに違反した場合に何が起こるかについて、ドキュメントは具体的な保証をしていないということです。とにかく呼び出しが機能する場合があります。とにかく通話が機能する場合がありますが、偶数年の9月のみです。とにかく呼び出しが機能する場合がありますが、メモリアドレスが4の倍数である場合に限ります(これは、読み取り操作に関係する特定のハードウェアおよびデバイスドライバーに依存する可能性があります。マシンで機能するという理由だけで機能しません。 tはそれが他の誰かに作用することを意味します。)

そもそもFILE_FLAG_NO_BUFFERING一緒に使用するのは良い考えではありません。なぜなら、基になる呼び出しに変更せずに指定したアドレスを渡すことが実際に保証されるとは思えないからです。代わりに、P / Invokeを使用して、基盤となるAPI関数を直接呼び出します。.NETが特定の配置でメモリを割り当てる方法を提供しているかどうかわからないため、この方法でメモリを割り当てる必要がある場合もあります。FileStreamFileStreamReadFile

于 2012-09-11T22:36:46.813 に答える
2

FILE_FLAG_NO_BUFFERINGを使用してCreateFileを直接呼び出し、FileStreamを使用して開く前に閉じるだけで、同じ効果が得られます。

于 2016-04-28T14:04:18.933 に答える