Потеря питания после того, как StreamWriter.Close() создает пустой файл, почему?

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

  •  07-07-2019
  •  | 
  •  

Вопрос

Хорошо, давайте объясним;Я разрабатываю систему, в которой может произойти сбой питания в любой момент времени, и я тестирую один момент сразу после того, как я записал файл с помощью StreamWriter.Код ниже:

// 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);

Записывает содержимое shellConfigWriterList строк) в файл, используемый в качестве временного хранилища, затем он копируется поверх оригинала.Теперь, после завершения выполнения этого кода, питание пропадает, при повторном запуске файла файл Game.cfg существует и имеет правильный размер, но совершенно пуст.Сначала я думал, что это связано с включенным Write-Caching на жестком диске, но даже при его выключении это все равно происходит (хотя и реже).

Любые идеи будут очень приветствоваться!

Обновлять: Итак, после удаления .Close() заявления и звонки .Flush() после каждой операции записи файлы по-прежнему остаются пустыми.Я мог бы пойти еще дальше и сначала создать резервную копию исходного файла, прежде чем создавать новый, и тогда у меня будет достаточно резервных копий для проверки целостности, но я не думаю, что это поможет решить основную проблему ( что когда я говорю ему записать, сбросить и закрыть файл...Это не так!).

Это было полезно?

Решение

Не позволяйте ОС буферизовать выходные данные с помощью параметра FileOptions конструктора объекта 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();
    }

Другие советы

Во-первых, вам не обязательно звонить shellConfigWriter.Close() там.Тем using заявление позаботится об этом.Вместо этого, чтобы защититься от сбоя питания, вы можете позвонить shellConfigWriter.Flush().


Обновлять
Еще кое-что, что вы, возможно, захотите принять во внимание, заключается в том, что если сбой в подаче электроэнергии действительно может произойти в любой время это может произойти в середине записи, так что в файл попадут только некоторые байты.На самом деле нет никакого способа остановить это.

Для защиты от таких сценариев обычно используют файлы флагов состояния/условия.Вы используете существование или отсутствие в файловой системе нулевого файла с определенным именем, чтобы сообщить вашей программе, откуда ей следует продолжить работу при возобновлении работы.Тогда вы не будете создавать и уничтожать файлы, вызывающие определенное состояние, пока не конечно вы достигли этого состояния и завершили предыдущее.

Обратной стороной здесь является то, что это может означать, что время от времени приходится выбрасывать много работы.Но преимущество в том, что это означает, что функциональная часть вашего кода выглядит нормально:для того, чтобы сделать систему достаточно надежной, нужно проделать очень немного дополнительной работы.

Вы хотите установить AutoFlush = true;

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top