FileStream ya no sincroniza el desplazamiento de archivo con el sistema operativo

Para mejorar el rendimiento, FileStream ya no sincroniza el desplazamiento de archivo con el sistema operativo.

Descripción del cambio

En versiones anteriores de .NET, FileStream sincroniza el desplazamiento de archivo con el sistema operativo (SO) Windows cuando lee o escribe en un archivo. Sincroniza el desplazamiento mediante una llamada a SetFilePointer, que es una llamada del sistema costosa. A partir de .NET 6, FileStream ya no sincroniza el desplazamiento de archivo, sino que simplemente mantiene el desplazamiento en memoria. FileStream.Position siempre devuelve el desplazamiento actual, pero si obtiene el identificador de archivo de FileStream.SafeFileHandle y consulta al sistema operativo para obtener el desplazamiento de archivo actual mediante una llamada del sistema, el valor de desplazamiento será 0.

El código siguiente muestra cómo difiere el desplazamiento de archivo entre las versiones anteriores de .NET y .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
    }
}

Versión introducida

.NET 6

Motivo del cambio

Este cambio se ha incorporado para mejorar el rendimiento de las lecturas y escrituras asincrónicas y para solucionar los problemas siguientes:

Con este cambio, las operaciones de ReadAsync son hasta dos veces más rápidas, y las operaciones de WriteAsync hasta cinco veces más rápidas.

  • Modifique cualquier código que dependa de la sincronización del desplazamiento.

  • Para habilitar el comportamiento de .NET 5 en .NET 6, especifique un modificador AppContext o una variable de entorno. Al establecer el modificador en true, opta por no recibir todas las mejoras de rendimiento realizadas en FileStream en .NET 6.

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

    Nota

    Este modificador solo está disponible en .NET 6. Se quitó en .NET 7.

API afectadas

Ninguno.

Consulte también