对于小型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文件

使用示例

 // Filepath:带写.xml文件路径;FindKey:待查找结点名称
// xeList:要新增的XElement结点列表
string FindKey = "Task";
var items = XStreamingElementHelper(Filepath, FindKey);
items = items.Concat(xeList);
var xml = new XStreamingElement
("Root",
from item in items
select item
); // 文件替换
var newFile = Filepath + "TEMP";
xml.Save(newFile);
System.IO.File.Delete(Filepath);
System.IO.File.Move(newFile, Filepath); GC.Collect();

XStreamingElement实现写文件写

参考

XStreamingElement类 - msdn

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>

上面代码中,必须是 &,而不能是 &amp;

示例代码

 string fileName = "sqh";
string fileDir = Directory.GetCurrentDirectory() + "/";
string xmlFilepath = fileDir + fileName + ".xml";
string txtFilepath = fileDir + fileName + ".txt";
if(!File.Exists(xmlFilepath))
{
// 创建.txt文件
File.Create(txtFilepath).Close(); // 创建.xml文件
string type = string.Format("<!ENTITY events SYSTEM \"{0}.txt\">", fileName);
XDocument XDoc = new XDocument(
new XDocumentType("Root", null, null, type),
new XElement("Root", "&events;")
);
XDoc.Save(xmlFilepath);
}
else
{
StreamWriter sw = File.AppendText(txtFilepath);
XmlTextWriter xtw = new XmlTextWriter(sw);
xtw.Formatting = Formatting.Indented; // 缩进格式
xtw.Indentation = ; // 新增结点
xtw.WriteStartElement("event");
xtw.WriteElementString("key", "value");
xtw.WriteEndElement(); xtw.WriteWhitespace(Environment.NewLine); // 换行,必须带
xtw.Close();
}

XML = .xml + .txt

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

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?

如何使用: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

C# - 操作大型XML文件的更多相关文章

  1. C# 读取大型Xml文件

    这篇博客将介绍在C#中如何读取数据量很大的Xml文件.请看下面的Xml文件, <?xml version="1.0" encoding="utf-8"?& ...

  2. 操作引入xml文件的书包(定位到指定节点)

    定位到指定节点:e0.1 <chtml><we>@{_samples/test.xml:HtokID=e0.1}</we></chtml> 上述表达式表 ...

  3. php对xml文件进行CURD操作

    XML是一种数据存储.交换.表达的标准: - 存储:优势在于半结构化,可以自定义schema,相比关系型二维表,不用遵循第一范式(可以有嵌套关系): - 交换:可以通过schema实现异构数据集成: ...

  4. PHP操作XML文件学习笔记

    原文:PHP操作XML文件学习笔记 XML文件属于标签语言,可以通过自定义标签存储数据,其主要作用也是作为存储数据. 对于XML的操作包括遍历,生成,修改,删除等其他类似的操作.PHP对于XML的操作 ...

  5. C#操作xml文件进行增、删、改

    进行操作的xml文件: products.xml <?xml version="1.0" encoding="utf-8"?><product ...

  6. 解析xml文件的几种技术与Dom4j与sax之间的对比

    一.解析xml文件的几种技术:dom4j.sax.jaxb.jdom.dom 1.dom4j dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常优秀的 ...

  7. python 解析 XML文件

    如下使用xml.etree.ElementTree模块来解析XML文件.ElementTree模块中提供了两个类用来完成这个目的: ElementTree表示整个XML文件(一个树形结构) Eleme ...

  8. C#窗体中读取修改xml文件

    由于之前没有操作过xml文件,尤其是在窗体中操作xml,脑子一直转不动,而且很抵制去做这个功能,终于还是突破了自己通过查询资料完成了这个功能,在此记录一下自己的成果. 功能说明:程序中存在的xml文件 ...

  9. 视频播放实时记录日志并生成XML文件

    需求描述: 在JWPlayer视频播放过程中,要求实时记录视频观看者播放.暂停的时间,并记录从暂停到下一次播放时所经过的时间.将所有记录保存为XML文件,以方便数据库的后续使用. 实现过程: 尝试1: ...

随机推荐

  1. validator 参数校验的常用注解

    @AssertFalse Boolean,boolean 验证注解的元素值是false @AssertTrue Boolean,boolean 验证注解的元素值是true @NotNull 任意类型 ...

  2. Opencv 图片直方图

    #include <iostream>#include <opencv2/opencv.hpp> using namespace std;using namespace cv; ...

  3. leetcode array解题思路

    Array *532. K-diff Pairs in an Array 方案一:暴力搜索, N平方的时间复杂度,空间复杂度N 数组长度为10000,使用O(N平方)的解法担心TLE,不建议使用,尽管 ...

  4. SQL 数据库 学习 006 如何设置一个用户名和密码

    我的电脑系统: Windows 10 64位 使用的SQL Server软件: SQL Server 2014 Express 先启动 SQL Server 2014 Management Studi ...

  5. RTC实时时钟-备份区域BKP--原理讲解

    RTC(Real Time Clock):实时时钟 BCD码:用4位2进制来表示10以内的十进制的形式. RTC的时钟源:LSE(32.768KHZ).HSE_RTC.LSI.经过一个精密校准(RTC ...

  6. JSTL详解实例

    JSTL标签库的使用是为类弥补html表的不足,规范自定义标签的使用而诞生的.在告别modle1模式开发应用程序后,人们开始注重软件的分层设计,不希望在jsp页面中出现java逻辑代码,同时也由于自定 ...

  7. Perl 学习笔记-模块

    1.Perl模块介绍 2个来源, 一个是随Perl发行版本一同打包, 只要安装了Perl就可以使用;  另一种是需要从CPAN上下载,自己安装.   寻找模块之前, 先检查系统上是否已经安装过了,   ...

  8. css3的那些高级选择器二

    在上个星期我介绍了css3的属性选择器,伪类选择器和结构伪类选择器,今天楼主继续把其它的css3选择器说完. 在css3中,共有11中UI状态伪类选择器,分别是E:hover,E:active,E:f ...

  9. 编写高质量代码改善C#程序的157个建议——建议138:事件和委托变量使用动词或形容词短语命名

    建议138:事件和委托变量使用动词或形容词短语命名 事件和委托使用场景是调用某个方法,只不过这个方法由调用者赋值.这决定了对应的变量应该以动词或形容词短语命名. 关于事件和委托变量妥当的命名示例如下: ...

  10. ARM启动代码中_main 与用户主程序main()的区别

    1.1  问题描述     __main函数的作用是什么呀?1.2  问题剖析     __main函数是C/C++运行时库的一个函数,嵌入式系统在进入应用主程序之前必须有一个初始化的过程,使用__m ...