FileStream 不再将文件偏移量与操作系统同步

为了提高性能,FileStream 不再将文件偏移量与操作系统同步。

更改说明

在 .NET 早期版本中,FileStream 在对文件执行读取或写入操作时会将文件偏移量与 Windows操作系统 (OS) 同步。 它通过调用 SetFilePointer 来同步偏移量,这是一个成本高昂的系统调用。 从 .NET 6 开始,FileStream 不再同步文件偏移量,而只是将偏移量保留在内存中。 FileStream.Position 始终返回当前偏移量,但如果从 FileStream.SafeFileHandle 获取文件句柄,然后使用系统调用在操作系统中查询当前文件偏移量,则偏移值将为 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

无。

另请参阅