C# - 操作大型XML文件
对于小型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实现写文件写
参考:
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>
上面代码中,必须是 &,而不能是 &
示例代码
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文件,& 会被转义成 & 是错误的,使用下面的创建方式
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);
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;
参考
C# - 操作大型XML文件的更多相关文章
- C# 读取大型Xml文件
这篇博客将介绍在C#中如何读取数据量很大的Xml文件.请看下面的Xml文件, <?xml version="1.0" encoding="utf-8"?& ...
- 操作引入xml文件的书包(定位到指定节点)
定位到指定节点:e0.1 <chtml><we>@{_samples/test.xml:HtokID=e0.1}</we></chtml> 上述表达式表 ...
- php对xml文件进行CURD操作
XML是一种数据存储.交换.表达的标准: - 存储:优势在于半结构化,可以自定义schema,相比关系型二维表,不用遵循第一范式(可以有嵌套关系): - 交换:可以通过schema实现异构数据集成: ...
- PHP操作XML文件学习笔记
原文:PHP操作XML文件学习笔记 XML文件属于标签语言,可以通过自定义标签存储数据,其主要作用也是作为存储数据. 对于XML的操作包括遍历,生成,修改,删除等其他类似的操作.PHP对于XML的操作 ...
- C#操作xml文件进行增、删、改
进行操作的xml文件: products.xml <?xml version="1.0" encoding="utf-8"?><product ...
- 解析xml文件的几种技术与Dom4j与sax之间的对比
一.解析xml文件的几种技术:dom4j.sax.jaxb.jdom.dom 1.dom4j dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常优秀的 ...
- python 解析 XML文件
如下使用xml.etree.ElementTree模块来解析XML文件.ElementTree模块中提供了两个类用来完成这个目的: ElementTree表示整个XML文件(一个树形结构) Eleme ...
- C#窗体中读取修改xml文件
由于之前没有操作过xml文件,尤其是在窗体中操作xml,脑子一直转不动,而且很抵制去做这个功能,终于还是突破了自己通过查询资料完成了这个功能,在此记录一下自己的成果. 功能说明:程序中存在的xml文件 ...
- 视频播放实时记录日志并生成XML文件
需求描述: 在JWPlayer视频播放过程中,要求实时记录视频观看者播放.暂停的时间,并记录从暂停到下一次播放时所经过的时间.将所有记录保存为XML文件,以方便数据库的后续使用. 实现过程: 尝试1: ...
随机推荐
- 【codevs3160】 LCS 【后缀自动机】
题意 给出两个字符串,求它们的最长公共子串. 分析 后缀自动机的基础应用. 比如两个字符串s1和s2,我们把s1建为SAM,然后根据s2跑,找出s2每个前缀的最长公共后缀. 我们可以理解为,当向尾部增 ...
- poj2796 Feel good
题目给出N个数,找出一段区间使得区间最小值乘区间和的值最大 其中N<=100000 分析: 单调队列(单调栈) 求出每个值作为最小值时最长的影响区间,然后枚举判断 这找出最长影响区间应该算是单调 ...
- CocoaPods私有库!!!!!!!!!!!(装逼特技)
1http://www.jianshu.com/p/4b63dfbd8be7 2 修改工程下的.podspec文件,如 注意1: 验证库是否正确: pod lib lint --verbose -- ...
- 钉钉开发笔记(六)使用Google浏览器做真机页面调试
注: 参考文献:https://developers.google.com/web/ 部分字段为翻译文献,水平有限,如有错误敬请指正 步骤1: 从Windows,Mac或Linux计算机远程调试And ...
- leetcode array解题思路
Array *532. K-diff Pairs in an Array 方案一:暴力搜索, N平方的时间复杂度,空间复杂度N 数组长度为10000,使用O(N平方)的解法担心TLE,不建议使用,尽管 ...
- webapi限流框架WebApiThrottle
为了防止网站意外暴增的流量比如活动.秒杀.攻击等,导致整个系统瘫痪,在前后端接口服务处进行流量限制是非常有必要的.本篇主要介绍下Net限流框架WebApiThrottle的使用. WebApiThro ...
- CSS实现input默认文字灰色有提示文字点击后消失鼠标移开显示
CSS实现input美化操作默认是为灰色,并且有提示 如下图 鼠标点击后文字消失,鼠标移开后文字显示 给input入下图添加代码 style="color:#cccccc; outline: ...
- 《Maven实战》
原创作者: 许晓斌 阅读:61148次 评论:19条 更新时间:2011-06-23 你是否早已厌倦了日复一日的手工构建工作?你是否对各个项目风格迥异的构建系统感到恐惧?Maven ...
- bootstrap小图标引用方法
<span class="glyphicon glyphicon-search"></span> <span class="glyphico ...
- sql server锁检测
有时候系统运行老感觉效率不高,并且有时候sql还有超时的报错,但是并发量并不高.通过排查定位sql是否有执行效率问题 -- 开事务, 以保持锁 BEGIN TRAN -- 更新 update tabl ...