次の方法で共有


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

変更理由

この変更は、非同期の読み取りと書き込みのパフォーマンスを向上させ、次の問題に対処するために導入されました。

この変更により、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

[なし] :

関連項目