#c_sharp #xml
Программа хранит ряд настроек в xml-файле. Если в момента записи настройки отключается питание компьютера, содержимое файла пропадает (сам файл остается, но если открыть - он пустой). Появилась идея сохранять изменения во временный файл, а затем переносить их в основной. Тогда, теоретически, должен повредиться только один из файлов при сбросе питания. Но на деле пропадает содержимое обоих файлов. Причина в коде? Или сам подход неправильный? Сохранение временного файла и его копирование в файл-оригинал представлено ниже: StreamWriter streamWriter = new StreamWriter(FileName_); BlockFile.WaitOne(); xmlDoc.Save(streamWriter); BlockFile.Release(); streamWriter.Dispose(); File.Copy(FileName_, FileName, true); В настоящее время код метода выглядит так: static public void SetValueOfParameter(string nodeName, string parameterName, string valueOfParameter) { BlockFile.WaitOne(); XmlDocument xmlDoc = new XmlDocument(); using (StreamReader streamReader = new StreamReader(FileName)) { xmlDoc.Load(streamReader); XmlElement xRoot = xmlDoc.DocumentElement; XmlNode node = xRoot.SelectSingleNode(nodeName); node.SelectSingleNode(parameterName).InnerText = valueOfParameter; streamReader.Close(); streamReader.Dispose(); } using (StreamWriter streamWriter = new StreamWriter(FileName_)) { xmlDoc.Save(streamWriter); streamWriter.Flush(); streamWriter.Close(); streamWriter.Dispose(); } FileInfo fInfo = new FileInfo(FileName_); if (fInfo.Exists && fInfo.Length>0) { if (File.Exists(FileName)) { File.Copy(FileName_,FileName,true); } } BlockFile.Release(); } Вместо File.Copy(FileName_,FileName,true); было испробовано удаление/перемещение. Эффект тот же - два файла пустые. Кэширование диска снято
Ответы
Ответ 1
Судя по описанию проблемы - пропаданию данных уже после того, как они были записаны на диск (а они были записаны, т.к. вы смогли скопировать файл) - у вас включено кэширование записи на диск. Проверить можно в свойствах диска в Device Manager. Кэширование записи безопасно только на дисках с автономным питанием (рейдах с батарейкой). Именно поэтому оно отключено по умолчанию. Если у вас обычный десктопный диск - данные будут теряться, и из кода на C# вы это никак не поборете.Ответ 2
Рекомендую сделать так: Вы сохраняете новый файл с именем settings_new.xml В случае успеха (проверка файла settings_new.xml на существование и ненулевую длину) удаляете файл settings.xml Переименовываете файл settings_new.xml в settings.xml (можно так же скопировать и удалить оригинал) При новом запуске приложения сначала ищете файл settings_new.xml. Если он существует и не пуст, значит произошел сбой питания или некорректное завершение работы программы. В этом случае доделываете операции 2 и 3. Если вы выполните этот алгоритм, то при любом сбое вы будете уверены настройки не пропадут.Ответ 3
Могу еще предложить не такой красивый, но гарантированно сохраняющий данные вариант: Создайте папку settings, сохраняйте файлы туда с timestamp, например 1494856800.xml При запуске программы ищите наиболее новый файл (максимальный timestamp) с ненулевой длинной. Удаляете все файлы кроме найденного (эту операцию для надежности можно поменять на "Удаляете все файлы, кроме 10 последних") UPD: Добавил пример кода: static public void SetValueOfParameter(string nodeName, string parameterName, string valueOfParameter) { // BlockFile.WaitOne(); string old_filename = get_setting_filename(); string new_filename = DateTime.Now.ToFileTimeUtc().ToString(); XmlDocument xmlDoc = new XmlDocument(); using (StreamReader streamReader = new StreamReader(old_filename)) { xmlDoc.Load(streamReader); XmlElement xRoot = xmlDoc.DocumentElement; XmlNode node = xRoot.SelectSingleNode(nodeName); node.SelectSingleNode(parameterName).InnerText = valueOfParameter; streamReader.Close(); streamReader.Dispose(); } using (StreamWriter streamWriter = new StreamWriter(new_filename)) { xmlDoc.Save(streamWriter); streamWriter.Flush(); streamWriter.Close(); streamWriter.Dispose(); } remove_old_files(); // BlockFile.Release(); } static public string get_setting_filename() { DirectoryInfo d = new DirectoryInfo("settings"); FileInfo[] Files = d.GetFiles("*.xml"); DateTime min_date = DateTime.MinValue; string filename = ""; // ищем не пустой файл с максимальной датой foreach (FileInfo file in Files) { // 4 - Чтобы файл не состоял только из символа окончания файла if (file.LastWriteTimeUtc > min_date && file.Length > 4) { min_date = file.LastWriteTimeUtc; filename = file.Name; } } return filename; } static public void remove_old_files() { DirectoryInfo d = new DirectoryInfo("settings"); FileInfo[] Files = d.GetFiles("*.xml"); DateTime min_date = DateTime.MinValue; int count_save_files = 10; foreach (FileInfo file in Files.OrderBy(f => f.LastWriteTime).Reverse().ToList()) { // Проверяем что файл не пустой if (file.Length > 4) { // Не удаляем файлы настроек за последние сутки, независимо от количества if (file.LastWriteTime < DateTime.Now.AddDays(-1)) { // Сохраняем 10 последних файлов (помимо последних суток) if (count_save_files > 0) { count_save_files--; } else { File.Delete(file.Name); } } } else { // Удаляем любые поврежденные файлы File.Delete(file.Name); } } }Ответ 4
Доброго времени суток! Последовательность должна быть такой: Вариант 1: Открытие и работа с файлом 1) Проверяете существование ~settings.xml 1.1) Проверяете валидность файла ~settings.xml 2.1) Если существует и валиден то открываете его с доступом на чтение иначе удаляете его и переходите к пункту 3 2.2) Открываете файл settings.xml с доступом на запись 2.3) Записываете содержимое файла ~settings.xml в settings.xml 2.4) Закрываете файлы. Удаляете ~settings.xml (далее работает по пунктам следующим пунктам) 3) Если файл ~settings.xml не существует, то открываете файл settings.xml с доступом на чтение 4) Создаете файл ~settings.xml и открываете с доступом на запись 5) Работаете с файлом ~settings.xml Сохранение результатов 1) Закрываете оба файла 2) Открываете файл ~settings.xml с доступом на чтение и файл settings.xml с доступом на запись 3) Перезаписываете файл settings.xml содержимым файла ~settings.xml 4) Закрываете оба файла. Удаляете ~settings.xml Вариант 2: Открытие и работа с файлом 1) Проверяете существование ~settings.xml 1.1) Проверяете валидность файла ~settings.xml 2.2) Если ~settings.xml существует и валиден то удаляете settings.xml иначе удяляете его и переходите к пункту 3 2.3) Копируете файл ~settings.xml и создаете новый файл с названием settings.xml 2.4) Удаляете ~settings.xml (далее работает по пунктам следующим пунктам) 3) Если файл ~settings.xml не существует, то копируете settings.xml и создаете новый файл с названием ~settings.xml 4) Работаете с файлом ~settings.xml (На этом этапе можно открыть файл ~settings.xml с доступом на запись) Сохранение результатов 1) Закрываете файл ~settings.xml 2) Удаляете файл settings.xml 3) Копируете файл ~settings.xml и создаете файл с названием settings.xml 4) Удаляете ~settings.xml Этот алгоритм должен предотвратить полную потерю данныхОтвет 5
xml заменили на базу sqlite. Все наладилось
Комментариев нет:
Отправить комментарий