Pérdida de potencia después de StreamWriter.Close () produce un archivo en blanco, ¿por qué?

StackOverflow https://stackoverflow.com/questions/1427288

  •  07-07-2019
  •  | 
  •  

Pregunta

Ok, entonces para explicar; Estoy desarrollando un sistema que puede sufrir una falla de energía en cualquier momento, un punto que estoy probando es directamente después de haber escrito un archivo usando un StreamWriter. El siguiente código:

// 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 (una List de cadenas) en un archivo utilizado como almacén temporal, luego se copia sobre el original. Ahora, después de que este código haya terminado de ejecutarse, se pierde la energía, al volver a iniciar la copia de seguridad, el archivo Game.cfg existe y tiene el tamaño correcto, pero está completamente en blanco. Al principio pensé que esto se debía a que el almacenamiento en caché de escritura estaba habilitado en el disco duro, pero incluso con él apagado todavía ocurre (aunque con menos frecuencia).

¡Cualquier idea sería muy bienvenida!

Actualización: Ok, así que después de eliminar las declaraciones .Close () y llamar a .Flush () después de cada operación de escritura, los archivos aún terminar 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, vacíe y cierre un archivo ... ¡No lo hace!).

¿Fue útil?

Solución

Evite que el SO almacene la salida en el búfer utilizando 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();
    }

Otros consejos

En primer lugar, no tiene que llamar a shellConfigWriter.Close () allí. La instrucción using se encargará de ello. Lo que quizás desee hacer en su lugar para protegerse contra fallas de energía es llamar a shellConfigWriter.Flush () .


Actualización
Otra cosa que quizás desee considerar es que si una falla de energía realmente puede ocurrir en cualquier momento, podría ocurrir en medio de una escritura, de modo que solo algunos de los bytes lleguen a un archivo. Realmente no hay forma de detener eso.

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

La desventaja aquí es que podría significar tirar mucho trabajo de vez en cuando. Pero el beneficio es que significa que la parte funcional de su código se ve normal: hay muy poco trabajo adicional para hacer que el sistema sea lo suficientemente robusto.

Desea configurar AutoFlush = true;

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top