Compartir a través de


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

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

Descripción del cambio

En versiones anteriores de .NET, FileStream sincroniza el desplazamiento de archivos con el sistema operativo 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 del archivo y, en su lugar, simplemente mantiene el desplazamiento en la 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 introdujo para mejorar el rendimiento de las lecturas y escrituras asincrónicas y solucionar los siguientes problemas:

Con este cambio, ReadAsync las operaciones son hasta dos veces más rápidas y WriteAsync las operaciones son 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, debe especificar un AppContext conmutador o una variable de entorno. Al configurar el interruptor en true, opta por no participar en todas las mejoras de rendimiento realizadas a FileStream en .NET 6.

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

    Nota:

    Este conmutador solo está disponible en .NET 6. Se eliminó en .NET 7.

Las APIs afectadas

Ninguno.

Consulte también