2009-09-15 12 views
6

Ok, entonces para explicar; Estoy desarrollando para un sistema que puede sufrir un corte de energía en cualquier momento, un punto que estoy probando es inmediatamente después de haber escrito un archivo usando StreamWriter. El código de abajo:Power Loss después de que StreamWriter.Close() produzca un archivo en blanco, ¿por qué?

// Write the updated file back out to the Shell directory. 
using (StreamWriter shellConfigWriter = 
     new StreamWriter(@"D:\xxx\Shell\Config\Game.cfg.bak")) 
{ 
    for (int i = 0; i < configContents.Count; i++) 
    { 
     shellConfigWriter.WriteLine(configContents[i]); 
    } 
    shellConfigWriter.Close(); 
} 

FileInfo gameCfgBackup = new FileInfo(@"D:\xxx\Shell\Config\Game.cfg.bak"); 
gameCfgBackup.CopyTo(@"D:\xxx\Shell\Config\Game.cfg", true); 

escribe el contenido de shellConfigWriter (un List de cuerdas) en un archivo utilizado como un almacén temporal, entonces se copia sobre el original. Ahora, después de que este código haya terminado de ejecutarse, se pierde la alimentación, al volver a iniciarse, aparece el archivo Game.cfg y tiene el tamaño correcto, pero está completamente vacío. Al principio, pensé que esto se debía a que Write-Caching estaba habilitado en el disco duro, pero incluso con eso, aún ocurre (aunque con menos frecuencia).

¡Cualquier idea sería bienvenida!

Actualización: Ok, así que después de la eliminación de las declaraciones .Close() y llamando .Flush() después de cada operación de escritura los archivos aún terminan en blanco. Podría ir un paso más allá y crear primero una copia de seguridad del archivo original, antes de crear el nuevo, y luego tengo suficientes copias de seguridad para hacer una verificación de integridad, pero no creo que ayude a resolver el problema subyacente (que cuando le digo que escriba, enjuague y cierre un archivo ... ¡No lo hace!).

+0

es 'Game.cfg.bak' en blanco así? –

+0

Sí, ambos están en blanco. :( – Siyfion

+2

C# tiene un búfer, el sistema operativo tiene un búfer o dos y su disco físico tiene un búfer. Creo que solo puede influir en los dos primeros desde C#. Siempre perderá algunos datos en una situación de pérdida de potencia, el la pregunta es cuánto. – Pod

Respuesta

11

Mantener el sistema operativo de amortiguar la salida usando el parámetro FileOptions del constructor del objeto FileStream:

using (Stream fs = new FileStream(@"D:\xxx\Shell\Config\Game.cfg.bak", FileMode.Create, FileAccess.Write, FileShare.None, 0x1000, FileOptions.WriteThrough)) 
    using (StreamWriter shellConfigWriter = new StreamWriter(fs)) 
    { 
     for (int i = 0; i < configContents.Count; i++) 
     { 
      shellConfigWriter.WriteLine(configContents[i]); 
     } 
     shellConfigWriter.Flush(); 
     shellConfigWriter.BaseStream.Flush(); 
    } 
+0

¡Fantástico! Great find;) – Siyfion

+1

Una alternativa al "nuevo FileStream" es el método File.Create estático: "File.Create (@" D: \ xxx \ Shell \ Config \ Game.cfg.bak ", 0x1000, FileOptions.WriteThrough, null) ". Tiene algunos parámetros menos y puede parecer más limpio en el código. –

6

En primer lugar, no tiene que llamar al shellConfigWriter.Close() allí. La declaración using se ocupará de ello. Lo que podría querer hacer para protegerse contra fallas de energía es llamar al shellConfigWriter.Flush().


actualización
Otra cosa que puede que desee tener en cuenta es que si una falla de energía realmente puede suceder en cualquier momento, podría suceder en el medio de una escritura, de modo que sólo una parte de la los bytes lo hacen a un archivo. Realmente no hay forma de detener eso.

Para protegerse de estos escenarios, un procedimiento común es utilizar archivos de indicadores de estado/condición. Utiliza la existencia o inexistencia en el sistema de archivos de un archivo de cero bytes con un nombre particular para indicarle a tu programa dónde retomar cuando se reanude. Entonces no crea ni destruye los archivos que activan un estado particular hasta que esté seguro haya alcanzado ese estado y haya completado el anterior.

El inconveniente aquí es que puede significar perder mucho trabajo de vez en cuando. Pero el beneficio es que significa que la parte funcional de su código parece normal: hay muy poco trabajo adicional para hacer que el sistema sea lo suficientemente robusto.

+0

De acuerdo, no tenía originalmente el método .Close() por esa razón exacta, ¡pero me estaba quedando sin cosas para intentar! Intento enrojecer después de cada llamada de escritura, vea qué sucede entonces. – Siyfion

+0

Sin suerte, todavía no escribió una sola línea. – Siyfion

0

desea establecer AutoFlush = true;

+0

Sí, podría, pero para el propósito de este código de ejemplo, es 1 línea de cualquier manera; enjuague cada iteración o configure AutoFlush en verdadero. Todavía produce el mismo resultado, que es que todavía produce un archivo en blanco. – Siyfion

+0

¿Estás seguro de que no estás simplemente escribiendo líneas en blanco en el archivo? ; p – leppie

Cuestiones relacionadas