В С# есть ли способ добавить XML node в файл на диске БЕЗ его загрузки?

У меня есть очень простая структура/файл XML на диске, что-то вроде:

<root>
    <data timestamp="dd-mm-yyyy" type="comment">kdkdkdk</data>
    <data timestamp="dd-mm-yyyy" type="event">kdkdkdkgffgfdgf</data>
    <data timestamp="dd-mm-yyyy" type="something">kddsdsfsdkdkdk</data>
</root>

XML будет, как уже упоминалось, во внешнем файле на диске. Поскольку файл может расти довольно большой (фактически "обрезанный" каждые две недели), я не хочу сначала загружать XML файл, чтобы добавить новый node...

Есть ли способ добавить новый node, как это? его можно просто добавить в верхнюю/нижнюю и т.д., так как процесс, который на самом деле использует XML, сортирует его по метке времени в любом случае.

Я предполагаю, что грубый способ заключается в добавлении текста node в текст. Однако я думаю, что он добавил бы node ПОСЛЕ окончания тега

Любые идеи с благодарностью получили.. Дэвид.

Ответ 1

Здесь уже есть несколько достойных ответов, но просто для того, чтобы еще раз поправить это, уверены ли вы, что эти данные должны храниться в виде XML файла?

Данные, которые вы храните, выглядят довольно просто (т.е. запись с тремя полями, датой, типом и некоторыми строковыми данными. Если вам не нужны какие-либо дополнительные преимущества, предоставляемые XML (см. здесь), то почему бы просто не использовать базовый CSV? Таким образом, вы можете просто добавлять к нему приложение так же, как файл журнала через File.AppendText("filename").

(Черт, возможно, даже можно использовать что-то вроде log4net для управления журналом и любой очистки домашнего хозяйства.)

Ответ 2

Не с каким-либо XML API или инструментом.

Вы можете открыть файл как текст, найти позицию </root> и начать переписывать оттуда. И, конечно, снова добавьте </root>.


Быстрый и грязный подход, это не очень надежный:

  • убедитесь, что вы подготовили исходный файл, после закрывающего тега должно быть ничего (без пробелов)
  • убедитесь, что вы используете кодировку ASCII или UTF8

====

string closeTag = "</root>";
int closeLength = Encoding.UTF8.GetBytes(closeTag).Length;

var fs = System.IO.File.Open(filename, System.IO.FileMode.Open);
fs.Position = fs.Length - closeLength;

var writer = new StreamWriter(fs);  // after the Position is set

writer.WriteLine(newTag);
writer.Write(closeTag);  // NOT WriteLine !!

writer.Close();
fs.Close();

И, конечно же, вы знаете об использовании блоков using() {}.

Ответ 3

Как-то вам нужно будет прочитать XML файл, так как вы не можете просто добавить node в документ.

Файл Xml может иметь только один корень, поэтому новый node должен быть добавлен после последнего элемента данных, но перед тегом закрытия корня. В противном случае xml недействителен.

Ответ 4

Зависит.

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

Однако, если вы определенно полностью знаете текстовый макет и кодировку файла, вы можете полностью его не читать и переписывать, открывая его как файл произвольного доступа (FileStream), пропустите до конца (минус "< root/" > "), добавьте туда новую запись и снова напишите "< root/" > ".

Ответ 5

Я не вижу способа сделать то, что вы делаете, не читая полный файл, но, как обходной путь, возможно, вы можете рассматривать файл как обычный текст, т.е. без корня node (он будет недействительным XML). Затем вы можете просто добавить новые узлы в файл как обычный текст. И так как ваш XML-процесс синтаксического анализа все равно загружает весь файл, он может добавить root node, прежде чем рассматривать его как XML.

Ответ 6

System.IO.FileInfo[] aryFi = di.GetFiles("*.xml");


foreach (System.IO.FileInfo fi in aryFi) {

 System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
 xmlDocument.Load(fi.FullName);

 XmlNode refelem = xmlDocument.LastChild;
 XmlNode newElem = xmlDocument.CreateNode("element", "something", "");
 newElem.InnerText = "sometext";
 xmlDocument.InsertAfter(newElem, refelem);
}

Я считаю, что лучшим вариантом будет открытие и вставка node. В любом случае вам нужно будет использовать IO, почему бы не сделать правильный путь?

Для одиночного файла

System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
 xmlDocument.Load("file path");

 XmlNode refelem = xmlDocument.LastChild;
 XmlNode newElem = xmlDocument.CreateNode("element", "something", "");
 newElem.InnerText = "sometext";
 xmlDocument.InsertAfter(newElem, refelem);

Ответ 7

Если вы не загружаете XML, вы имеете в виду не строить дерево DOM, VTD-XML - это единственный API, который позволяет вырезать фрагмент пасты или изменять постепенно. Кроме того, поскольку VTD-XML эффективен с точки зрения памяти, вам не придется беспокоиться о размере XML-документа. Аналогичная запись в Java находится в Как обновить большой XML файл. Обратите внимание, что vtd-xml доступен в Java, С#, C и С++.

Ответ 8

просто используйте

string s = File.ReadAllText(path)
s = s.replace("</root>", newnode + "</root>")
File.WriteAllText(s, path)