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 作業速度最多可達兩倍,而 WriteAsync 作業速度最多可達五倍。

  • 修改相依於同步之位移的任何程式碼。

  • 若要在 .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

無。

另請參閱