将新节点添加到xml结尾的最快方法?

Ram*_*oni 7 .net c# xml

我有一个大的xml文件(大约10 MB)以下简单的结构:

<Errors>
   <Error>.......</Error>
   <Error>.......</Error>
   <Error>.......</Error>
   <Error>.......</Error>
   <Error>.......</Error>
</Errors>
Run Code Online (Sandbox Code Playgroud)

我需要在</ Errors>标记之前的末尾添加一个新节点<Error>.什么是在.net中实现这一目标的最快方法?

tof*_*fi9 10

您需要使用XML包含技术.

你的error.xml(不会改变,只是一个存根.由XML解析器用来读取):

<?xml version="1.0"?>
<!DOCTYPE logfile [
<!ENTITY logrows    
 SYSTEM "errorrows.txt">
]>
<Errors>
&logrows;
</Errors>
Run Code Online (Sandbox Code Playgroud)

你的errorsrows.txt文件(更改,xml解析器不理解它):

<Error>....</Error>
<Error>....</Error>
<Error>....</Error>
Run Code Online (Sandbox Code Playgroud)

然后,向errorsrows.txt添加一个条目:

using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
    XmlTextWriter xtw = new XmlTextWriter(sw);

    xtw.WriteStartElement("Error");
    // ... write error messge here
    xtw.Close();
}
Run Code Online (Sandbox Code Playgroud)

或者您甚至可以使用.NET 3.5 XElement,并将文本追加到StreamWriter:

using (StreamWriter sw = File.AppendText("logerrors.txt"))
{
    XElement element = new XElement("Error");
    // ... write error messge here
    sw.WriteLine(element.ToString());
}
Run Code Online (Sandbox Code Playgroud)

另请参阅Microsoft的文章修改大型XML文件的高效技术


Col*_*ett 7

首先,我将取消对System.Xml.XmlDocument的限制,因为它是一个DOM,它需要在可以附加到内存之前解析并构建内存中的整个树.这意味着您的10 MB文本内存将超过10 MB.这意味着它是"内存密集型"和"耗时".

其次,我会取消System.Xml.XmlReader的资格,因为它需要先解析整个文件,然后才能到达可以附加到它的位置.您必须将XmlReader复制到XmlWriter中,因为您无法修改它.这需要先在内存中复制XML,然后才能附加到它.

XmlDocument和XmlReader的更快解决方案是字符串操作(它有自己的内存问题):

string xml = @"<Errors><error />...<error /></Errors>";
int idx = xml.LastIndexOf("</Errors>");

xml = xml.Substring(0, idx) + "<error>new error</error></Errors>";
Run Code Online (Sandbox Code Playgroud)

切掉结束标记,添加新错误,然后添加结束标记.

我想你可能会对此发疯,并将你的文件截断9个字符并附加到它上面.不必读取文件并让操作系统优化页面加载(只需加载最后一个块或其他东西).

System.IO.FileStream fs = System.IO.File.Open("log.xml", System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite);
fs.Seek(-("</Errors>".Length), System.IO.SeekOrigin.End);
fs.Write("<error>new error</error></Errors>");
fs.Close();
Run Code Online (Sandbox Code Playgroud)

如果您的文件为空或仅包含"<错误> </错误>",则会出现问题,通过检查长度可以轻松处理这两个问题.