Программа хранит ряд настроек в 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); было испробовано удаление/перемещение. Эффект тот же - два файла пустые. Кэширование диска снято
Судя по описанию проблемы - пропаданию данных уже после того, как они были записаны на диск (а они были записаны, т.к. вы смогли скопировать файл) - у вас включено кэширование записи на диск. Проверить можно в свойствах диска в Device Manager.
Кэширование записи безопасно только на дисках с автономным питанием (рейдах с батарейкой). Именно поэтому оно отключено по умолчанию. Если у вас обычный десктопный диск - данные будут теряться, и из кода на C# вы это никак не поборете.
Рекомендую сделать так:
Если вы выполните этот алгоритм, то при любом сбое вы будете уверены настройки не пропадут.
Доброго времени суток! Последовательность должна быть такой:
Вариант 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
Этот алгоритм должен предотвратить полную потерю данных
Могу еще предложить не такой красивый, но гарантированно сохраняющий данные вариант:
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);
}
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть XML файл, он лежит в сторонней от программы папкеКак из него считать информацию?
Здравствуйте! Есть три источника данных (реляционная ДБ, EF 6, database first)Знаю, как привести к виду один к одному