c# - ¿Cómo garantizar que todos los datos se hayan escrito físicamente en el disco?
.net filestream (6)
Bueno, podrías cerrar el archivo ... eso probablemente lo haría. En realidad, con la abstracción de HAL, la virtualización y el hardware del disco que ahora tienen más poder de procesamiento y memoria caché que las computadoras hace unos años, tendrá que vivir con la esperanza de que el disco haga su trabajo.
El sistema de archivos transaccionales nunca se materializó realmente ;-p Por supuesto, ¿podría considerar el uso de una base de datos como un back-end, y usar el sistema de transacción de eso?
Aparte: tenga en cuenta que no todas las transmisiones ni siquiera garantizan que Flush()
- por ejemplo, GZipStream
, etc. retienen un búfer en funcionamiento de datos no confirmados incluso después de una descarga - la única manera de hacer que purgue todo es Close()
.
Entiendo que el método de descarga de .NET FileStream solo escribe el búfer actual en el disco, pero depende del controlador de disco de Windows y del firmware del disco duro, esto no es garantía de que los datos estén físicamente escritos en el disco.
¿Existe un método .NET o Win32 que pueda darme esta garantía? Entonces, si hay pérdida de energía un nanosegundo después de que la llamada a este método vuelve, ¿aún puedo estar seguro de que todo está bien?
Simplemente hay demasiados niveles de abstracción para estar absolutamente seguro de que los datos están escritos en el disco, hasta el nivel de hardware.
No es brillante ni a prueba de tontos, pero ¿qué hay de volver a abrir el archivo una vez que está escrito en un proceso separado y verificar el tamaño o el contenido?
En Windows, mira FlushFileBuffers (Win32 API).
Me he dado cuenta de que .NET 4 #Flush (verdadero) no escribe realmente en el disco. Estábamos teniendo problemas extraños con datos dañados y encontré este informe de error en el sitio de MS:
La pestaña de detalles para el informe de errores tiene un programa de prueba que puede ejecutar que mostrará el problema;
- Escribe un montón de datos en el disco
-
fs.Flush(true)
. Esto no lleva tiempo (mucho más rápido de lo que posiblemente se pueda escribir en el disco). - Use win32 API
FlushFileBuffers
. Esto lleva mucho tiempo.
Me estoy cambiando a la llamada Win32 FlushFileBuffers ...
Stefan S. dijo:
Entiendo que el método de descarga de .NET FileStream solo escribe el búfer actual en el disco
No, .NET FileStream''s Flush solo escribe los búferes de .NET en la memoria caché del sistema operativo, no vacía la memoria caché del sistema operativo en el disco. Lamentablemente, el documento de MSDN en esta clase no dice eso. Para .NET <4.0, tendrá que llamar a Flush + Win32''s FlushFilebuffers:
using System.Runtime.InteropServices;
. . .
// start of class:
[DllImport("kernel32", SetLastError=true)]
private static extern bool FlushFileBuffers(IntPtr handle);
. . .
stream.Flush(); // Flush .NET buffers to OS file cache.
#pragma warning disable 618,612 // disable stream.Handle deprecation warning.
if (!FlushFileBuffers(stream.Handle)) // Flush OS file cache to disk.
#pragma warning restore 618,612
{
Int32 err = Marshal.GetLastWin32Error();
throw new Win32Exception(err, "Win32 FlushFileBuffers returned error for " + stream.Name);
}
Para .NET 4.0, puede usar el nuevo método flush (verdadero). 11/09/2012 actualización: informe de error de MS aquí dice que está roto, luego corregido, ¡pero no dice en qué versión o service pack se arregló! Suena como un error si el buffer interno .NET FileStream está vacío, el Flush (verdadero) ¿no hizo nada?
Los datos del archivo almacenados en el caché del sistema de archivos se almacenan en el disco. Normalmente, estos datos se escriben de forma lenta, en función de la posición del cabezal de escritura del disco. Tener un gigabyte de datos en caché es técnicamente posible, por lo que puede llevar bastante tiempo. Si esto es importante para usted, considere la opción FileOptions.WriteThrough
lugar.