xdocument сохранить добавление дополнительных символов

#c# #.net #xml

#c# #.net #xml

Вопрос:

Я использую XDocument для загрузки и сохранения файла конфигурации. Большую часть времени он работает корректно, но бывают случаи (кажущиеся случайными), когда он добавляет дополнительную информацию после последнего тега. Вот суть того, что происходит.

Предварительный запуск файла конфигурации:

 <?xml version="1.0" encoding="us-ascii"?>
<local>
</local>
  

код:

 XDocument config = new XDocument();
config = XDocument.Load(new FileStream(@"c:foo.xml", FileMode.Open, FileAccess.Read));
XElement fileEle = config.Root.Element("files");
XElement statsEle = new XElement("stats");
statsEle.Add(new XElement("one", "two"));
statsEle.Add(new XElement("three", "four"));
.
.
.
fileEle.Add(statsEle);
config.Save(new FileStream(@"c:foo.xml", FileMode.Create, FileAccess.Write), SaveOptions.None);
  

файл конфигурации после запуска:

 <?xml version="1.0" encoding="us-ascii"?>
<local>
    <files>
        <one>two</one>
        <three>four</three>
    </files>
</local>s>
</local>
  

Есть предложения? Понятия не имею, почему добавляются дополнительные символы. Иногда это дополнительный тег, иногда это разные символы, а иногда это работает правильно. Я пробовал загружать / сохранять, используя разные методы (XmlReader и т.д.), добавляя XML-теги разными способами .. после запуска X все они выдают одну и ту же ошибку. Спасибо за помощь!

Ответ №1:

У вас одновременно открыты два FileStream файла для одного и того же файла… один для чтения foo.xml , а другой для перезаписи. Это кажется очень проблематичным.

Я бы рекомендовал:

  • Удаление прочитанного, FileStream как только ваш XmlDocument файл будет загружен:
 using (FileStream fs = new FileStream(@"C:foo.xml", FileMode.Open, FileAccess.Read))
{
    config.Load(fs);
}
  
  • Используйте FileMode.Truncate при записи FileStream , чтобы файл был усечен до 0 байт, прежде чем вы начнете в него записывать.

Комментарии:

1. Хороший улов. Xdocument.Load(new FileStream)...)) Оставляет открытым зависший файл.

2. @Andrew хороший улов. Я все еще получал ошибки после закрытия файловых потоков, но, похоже, что открытие с помощью truncate устранило проблему. Спасибо!

3. @Eckstein: Если это решение работает, то использование XDocument.Load и config.Save(filename) тоже должно сработать.

4. Это то, что я понял.. кажется, должна быть такая же реализация под капотом.

5. После еще нескольких тестов загрузка и сохранение сработали. Возможно, DLL устарела.. Спасибо, Джон.

Ответ №2:

Я предполагаю, что что-то фактически перезаписывает (но не усекает) файл с меньшим количеством тегов — и то, что вы видите, является остатками большего XML-файла.

Я никогда не видел, чтобы LINQ to XML сам делал что-либо подобное.

Можете ли вы запустить те же тесты, которые всегда завершаются неудачей, но в режиме, когда каждая итерация записывает в новый файл вместо перезаписи старого?

Есть ли какая-либо причина, по которой вы загружаетесь непосредственно из FileStreams (которые никогда не закрываются, как указывает другой ответ) вместо того, чтобы просто использовать XDocument.Load(filename) , XDocument.Save(filename) ?

Комментарии:

1. это совершенно верно. Некоторое время назад я боролся с этим

2. все еще сталкивался с .Save, но запись в новый файл устранила проблему. Похоже, ошибочный дизайн заключается в том, что исходный файл не удаляется или что-то подобное перед записью. Или, может быть, мне просто не повезло 🙂 Спасибо!

3. @Eckstein: Вы уверены, что у вас нет нескольких потоков, выполняющих это? Это запись на общий сетевой ресурс или просто на локальный диск?

4. Это многопоточное приложение, но к файлу конфигурации никогда не обращается более одного потока. Запись на локальный диск.

Ответ №3:

Я видел это раньше… просто не могу придумать, как это решить. Я думаю, это как-то связано с тем, как вы сохраняете. Вам нужно убедиться, что вы перезаписали все. Я не могу вспомнить, является ли это filemode или options… или другой параметр