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: ...
随机推荐
- 混合开发Js bridge新秀-DSBridge iOS篇
这个DSBridge 和我之前开发做的混合开发 用的方式 很相似,所以觉得很是不错,推荐给你大家. DSBridge-IOS:https://github.com/wendux/DSBridge-IO ...
- 行走于Swift的世界中(转)
从Swift正式公布到现在,我基本一直在关注和摸索Swift.对于一门新语言来说,开荒阶段的探索自然是激动人心的,但是很多时候,资料的缺失和细节的隐藏也让人着实苦恼.最近几天的感受是,Swift 并不 ...
- 测试URL
http://localhost:8080/dmonitor-webapi/monitor/vm/342?r=1410331220921&indexes=cpu&indexes=mem ...
- lintcode-单例
单例 是最为最常见的设计模式之一.对于任何时刻,如果某个类只存在且最多存在一个具体的实例,那么我们称这种设计模式为单例.例如,对于 class Mouse (不是动物的mouse哦),我们应将其设计为 ...
- smarty 使用php函数
strtotime() time() <{if strtotime($activity.start_time) gt time()}> <a href="?action=d ...
- [Groovy]获取当前活动的Environment,获取response中节点的name和节点的value
import com.eviware.soapui.support.GroovyUtils import com.eviware.soapui.support.XmlHolder import org ...
- [Cookie] Clear Cookie
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport def myCookies = testRunner.testCa ...
- linux的操作
对tomcat的操作 打开终端 cd /java/tomcat#执行bin/startup.sh #启动tomcatbin/shutdown.sh #停止tomcat tail -f logs/cat ...
- C primer 编程练习 (不断更新)
目前在看<C Primer>,以后会经常在这篇博客里更新课后的编程练习题 第二章:编程练习 2.1 #include <stdio.h> int main(void) { pr ...
- 20169205实验二 Java面向对象程序设计
20169205实验二 Java面向对象程序设计 实验内容及步骤 (一)单元测试 1.三种代码 伪代码:以简洁的自然语言表明设计步骤: 产品代码:用以实现特定功能的程序或机器语言: 测试代码:用以对产 ...