对小型XML文件,利用XDocument和XMLDocument可以充分便利开展读写(推荐XDocument),但问题是XDocument和XMLDocument是In-Memory类型的,随着文件大小的增大,内存消耗会愈来愈老,同时读写速度会减低。本文总结如下几栽方法操作大型XML文件:

读 – Read

动XmlReader或XmlTextReader流式加载、解析XML文件。

static IEnumerable<XElement> XStreamingElementHelper(string uri, string FindKey)
{
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.IgnoreComments = true;
    settings.IgnoreWhitespace = true;

    using (XmlReader rd = XmlReader.Create(uri, settings))
    {
        rd.MoveToContent();
        while (!rd.EOF)
        {
            if(rd.NodeTyp == XElement && rd.Name == FindKey)
            {
                XElement item = XElement.ReadFrom(rd) as XElement;
                if (item != null)
                {
                    yield return item;
                }
            }
            else
            {
                rd.Read();
            }
        }
    }
}

其中,内部用XElement操作。  

写 – Write

此有开始前,先提供一个创建空的 xml 文档的代码

string filePath = Directory.GetCurrentDirectory() + "/123456.xml";
if (!File.Exists(filePath))
{
    XmlDocument xdInit = new XmlDocument();
    StringBuilder sb = new StringBuilder();
    sb.Append("<?xml version=\"1.0\" encoding=\"gb2312\" ?><Root>");
    sb.Append("</Root>");
    string strXml = sb.ToString();
    xdInit.LoadXml(strXml);
    xdInit.Save(filePath);
}

该方式变的 .xml 文档如下

<?xml version="1.0" encoding="gb2312"?>
<Root>
</Root>

抑或采用如下代码

if (!System.IO.File.Exists(filePath))
{
    System.IO.File.Create(filePath).Close();
    XDocument xdInit = new XDocument(
        new XElement("Root"));
    xdInit.Save(filePath);
    xdInit = null;
}

欠法变的 .xml 文档如下

<?xml version="1.0" encoding="utf-8"?>
<Root />

只顾,以上2栽格式等同,xml 文档默认的编码方式是 utf-8。

于拼接 xml 字符串时,要特别注意非法字符的转义处理:

System.Security.SecurityElement.Escape(str)

为业已是的特大型XML文件中追加新结点,不能够应用In-Memory的法子。推荐如下几种写方法:

1. XStreamingElement

问题引出:怎巨型xml文件;

应用示例

XML 1XML 2

 1 // Filepath:带写.xml文件路径;FindKey:待查找结点名称
 2 // xeList:要新增的XElement结点列表
 3 string FindKey = "Task";
 4 var items = XStreamingElementHelper(Filepath, FindKey);
 5 items = items.Concat(xeList); 
 6 var xml = new XStreamingElement
 7     ("Root",
 8         from item in items
 9         select item
10     );
11 
12 // 文件替换
13 var newFile = Filepath + "TEMP";
14 xml.Save(newFile);
15 System.IO.File.Delete(Filepath);
16 System.IO.File.Move(newFile, Filepath);
17 
18 GC.Collect();

XStreamingElement实现写文件写

参考

XStreamingElement类 –
msdn.aspx);

How to: Perform Streaming Transform of Large XML Documents (C#) –
msdn;

关于XStreamingElement vs
XElement;
 Linq to
Xml:XStreamingElement;

2. XML文本包含方法

运用包含文件 .txt 和 .xml实现大型XML文件的有效增加操作和修改操作:

  • .xml:格式正确的标准XML文件
  • .txt:XML片段

格式正确的XML文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Root [<!ENTITY events SYSTEM "people.txt">]>
<Root>&events;</Root>

地方代码中,必须是 &,而未克是
&

演示代码

XML 3XML 4

 1 string fileName = "sqh";
 2 string fileDir = Directory.GetCurrentDirectory() + "/";
 3 string xmlFilepath = fileDir + fileName + ".xml";
 4 string txtFilepath = fileDir + fileName + ".txt";
 5 if(!File.Exists(xmlFilepath))
 6 {
 7     // 创建.txt文件
 8     File.Create(txtFilepath).Close();
 9     
10     // 创建.xml文件
11     string type = string.Format("<!ENTITY events SYSTEM \"{0}.txt\">", fileName);
12     XDocument XDoc = new XDocument(
13         new XDocumentType("Root", null, null, type),
14         new XElement("Root", "&events;")
15         );
16     XDoc.Save(xmlFilepath);
17 }
18 else
19 {
20     StreamWriter sw = File.AppendText(txtFilepath);
21     XmlTextWriter xtw = new XmlTextWriter(sw);
22     xtw.Formatting = Formatting.Indented;  // 缩进格式
23     xtw.Indentation = 2;
24     
25     // 新增结点
26     xtw.WriteStartElement("event");
27     xtw.WriteElementString("key", "value");
28     xtw.WriteEndElement();
29     
30     xtw.WriteWhitespace(Environment.NewLine); // 换行,必须带
31     xtw.Close();
32 }

XML = .xml + .txt

上面代码创建的XML文件,& 会被转义成 & 是错误的,使用下的创导方式

XmlDocument xd = new XmlDocument();
string head = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
string docType = string.Format("<!DOCTYPE Root [<!ENTITY Persons SYSTEM \"{0}.txt\">]>", txtFileName);
string rootBody = "<Root>&Persons;</Root>";
StringBuilder sb = new StringBuilder();
sb.Append(head); sb.Append(docType); sb.Append(body);
string strXml = sb.ToString();
xd.LoadXml(strXml);
xd.Save(filePath);

只顾,每写一次.txt文件,必须上加如下代码,否则会油然而生结点粘结的情形

xtw.WriteWhitespace(Environment.NewLine);

这里可以使用 StreamWriter,亦可使 FileStream,代码如下

FileStream filestream = new FileStream(FileName, FileMode.Append);
XmlTextWriter xtw = new XmlTextWriter(filestream, Encoding.Default);
xtw.Formatting = Formatting.Indented;
xtw.Indentation = 2;
... ...
xtw.Close();
filestream.Close();

假使采用该 .txt + .xml
方法,应以如下方式读取 .xml 文件

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Parse;  // 必须的
settings.ValidationType = ValidationType.None; // 可选的
settings.IgnoreComments = true;
//settings.IgnoreWhitespace = true;  // 视while{}中代码情况
XmlReader rd = XmlReader.Create(filepath, settings);

while (rd.Read())
{
    if (rd.NodeType == XmlNodeType.Element && rd.Name == "person")
    { ... }   
}

只顾,因为如果用 XmlReaderSettings 设置读取配置,因此只能采取
XmlReader,而非克使用如下代码

XmlTextReader rd = new XmlTextReader(filepath);

参考:修改大型 XML
文件之管事办法 –
MSDN;

3. log4net

引用:using log4net.dll

题目引出:如何log4net to xml?;

哪些XML以:Write a class Deriving from XmlLayoutBase,
override the FormatXml method and instruct your appender to
use. 

4. 文本拆分

xml/txt
写文件时,文件会越加深,可以装时间点或者文件大小限制,将那个文件拆分成基本上个稍文件。

// 文件大小
FileInfo fileInfo = new FileInfo(FilePath);
double fileSize = System.Math.Ceiling(fileInfo.Length / 1024.0);

拖欠办法可行使
log4net 实现,具体可参看:log4net –
sqh;

参考

有关XML格式化的题目;xml日志乱码的问题;

争以log4net写XML;

相关文章

网站地图xml地图