FileStream でのファイル オフセットと OS の同期を廃止
パフォーマンス向上のため、FileStream では、ファイル オフセットがオペレーティング システムと同期されなくなりました。
変更の説明
.NET の以前のバージョンでは、ファイルの読み取りまたは書き込みが行われるときに、FileStream によってファイル オフセットが Windows オペレーティング システム (OS) と同期されます。 オフセットを同期するために呼び出される SetFilePointer は、負荷の高いシステム コールです。 .NET 6 以降の FileStream では、ファイル オフセットは同期されなくなり、オフセットがメモリ内に保持されるだけです。 FileStream.Position からは常に現在のオフセットが返されますが、FileStream.SafeFileHandle からファイル ハンドルを取得し、システム コールを使用して現在のファイル オフセットを OS に照会した場合、オフセット値は 0 になります。
次のコードは、.NET の以前のバージョンと .NET 6 でファイル オフセットがどのように異なるかを示したものです。
[DllImport("kernel32.dll")]
private static extern bool SetFilePointerEx(SafeFileHandle hFile, long liDistanceToMove, out long lpNewFilePointer, uint dwMoveMethod);
byte[] bytes = new byte[10_000];
string path = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true))
{
SafeFileHandle handle = fs.SafeFileHandle;
await fs.WriteAsync(bytes, 0, bytes.Length);
Console.WriteLine(fs.Position); // 10000 in all versions
if (SetFilePointerEx(handle, 0, out long currentOffset, 1 /* get current offset */))
{
Console.WriteLine(currentOffset); // 10000 in .NET 5, 0 in .NET 6
}
}
導入されたバージョン
.NET 6
変更理由
この変更は、非同期の読み取りと書き込みのパフォーマンスを向上させ、次の問題に対処するために導入されました。
- Win32 FileStream で、すべての ReadAsync 呼び出しにシークが発行される
- FileStream.Windows useAsync WriteAsync の呼び出しで、API がブロックされる
この変更により、ReadAsync 操作は最大で 2 倍速くなり、WriteAsync 操作は最大で 5 倍速くなります。
推奨アクション
オフセットが同期されることに依存するすべてのコードを変更します。
.NET 6 で .NET 5 の動作を有効にするには、
AppContext
スイッチまたは環境変数を指定します。 スイッチをtrue
に設定すると、.NET 6 でFileStream
に対して行われたすべてのパフォーマンス向上策が無効になります。{ "configProperties": { "System.IO.UseNet5CompatFileStream": true } }
set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1
注意
このスイッチは .NET 6 でのみ使用できます。 .NET 7 では削除されました。
影響を受ける API
[なし] :
関連項目
.NET