Поделиться через


FileStream больше не синхронизирует смещение файла с ОС

Для повышения производительности FileStream больше не синхронизирует смещение файла с операционной системой.

Описание изменения

В предыдущих версиях .NET FileStream синхронизирует смещение файла с операционной системой (ОС) Windows при считывании файла или записи в файл. Он синхронизирует смещение путем вызова 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 выполняются в два раза быстрее, а операции WriteAsync — в пять раз быстрее.

  • Измените код, который основывался на синхронизации со смещением.

  • Чтобы включить поведение .NET 5 в .NET 6, укажите параметр AppContext или переменную среды. Установив для параметра значение true, вы отказываетесь от всех улучшений производительности, имеющихся FileStream в .NET 6.

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

    Примечание.

    Этот параметр доступен только в .NET 6. Он был удален в .NET 7.

Затронутые API

Нет.

См. также