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
Причина изменения
Это изменение было введено для повышения производительности асинхронных операций чтения и записи, а также для решения следующих проблем:
- Win32 FileStream выполняет поиск при каждом вызове ReadAsync
- FileStream.Windows использует асинхронные вызовы WriteAsync, которые блокируют API
Благодаря этому изменению операции 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
Нет.