FileStream synchronisiert den Dateioffset nicht mehr mit dem Betriebssystem

Zur Leistungsverbesserung synchronisiert FileStream den Dateioffset nicht mehr mit dem Betriebssystem.

Beschreibung der Änderung:

In früheren .NET-Versionen synchronisiert FileStream den Dateioffset mit dem Windows-Betriebssystem, wenn Lese- oder Schreibvorgänge für eine Datei ausgeführt werden. Der Offset wird synchronisiert, indem SetFilePointer aufgerufen wird. Dabei handelt es sich um einen ressourcenintensiven Systemaufruf. Ab .NET 6 synchronisiert FileStream den Dateioffset nicht mehr. Stattdessen wird der Offset nur im Arbeitsspeicher gespeichert. FileStream.Position gibt immer den aktuellen Offset zurück. Wenn Sie jedoch das Dateihandle von FileStream.SafeFileHandle erhalten und das Betriebssystem mithilfe eines Systemaufrufs nach dem aktuellen Dateioffset abfragen, lautet der Offsetwert 0.

Der folgende Code zeigt, wie sich der Dateioffset zwischen früheren .NET-Versionen und .NET 6 unterscheidet.

[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
    }
}

Eingeführt in Version

.NET 6

Grund für die Änderung

Diese Änderung wurde eingeführt, um die Leistung asynchroner Lese- und Schreibvorgänge zu verbessern und die folgenden Probleme zu lösen:

Mit dieser Änderung sind ReadAsync-Vorgänge bis zu zweimal schneller, und WriteAsync-Vorgänge sind bis zu fünfmal schneller.

  • Ändern Sie Code, der davon abhing, dass der Offset synchronisiert wird.

  • Zum Aktivieren des .NET 5-Verhaltens in .NET 6 geben Sie einen AppContext-Parameter oder eine Umgebungsvariable an. Indem Sie den Parameter auf true festlegen, können Sie alle Leistungsverbesserungen in .NET 6 deaktivieren, die an FileStream vorgenommen wurden.

    {
        "configProperties": {
            "System.IO.UseNet5CompatFileStream": true
        }
    }
    
    set DOTNET_SYSTEM_IO_USENET5COMPATFILESTREAM=1
    

    Hinweis

    Diese Option ist nur in .NET 6 verfügbar. Sie wurde in .NET 7 entfernt.

Betroffene APIs

Keine.

Weitere Informationen