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: ...
随机推荐
- 【SPOJ - SUBLEX】Lexicographical Substring Search 【后缀自动机+dp】
题意 给出一个字符串和q个询问,每个询问给出一个整数k,输出第k大得子串. 分析 建后缀自动机,利用匹配边来解决.设d[v]为从状态v开始有多少不同的路径.这个显然是可以递推出来的.然后对于每个询问, ...
- RTX二次开发::检索 COM 类工厂中 CLSID 为 {79210E58-99EB-45D0-8890-763EFEAA143F} 的组件失败,
解决方法: 1.Interop.RTXSAPILib.dll这个是32位的 将IIS 应用程序池 启用32位应用程序 设置为true就可以了, 2.把编译好的程序选择X86平台运行,就好了 程序员的基 ...
- dll详解
[转]http://www.cnblogs.com/xuemaxiongfeng/articles/2461632.html 不解为什么要用WINAPI宏定义,查了后发现下面的定义.于是乎需要区别 _ ...
- [Email] 收发邮件的协议 : IMAP and SMTP , POP3 and SMTP
支持 IMAP 和 SMTP 的应用 与仅同步收件箱的 POP 不同,IMAP 同步所有电子邮件文件夹. 在电子邮件应用中使用以下设置. 接收 (IMAP) 服务器 服务器地址:imap-mail.o ...
- [SoapUI] 在某个测试步骤下面增加Script Assertion,运用 messageExchange 获取response content
import com.eviware.soapui.support.GroovyUtils import com.eviware.soapui.support.XmlHolder import org ...
- Java基础——常用类型转换
关于类型转化问题: (1)String--------->char / char[ ] String str = "ab"; char str1 = str.charAt(0 ...
- rest-framework-----url控制
一:自定义路由(原始方式) from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^books/ ...
- MySQL 存储过程 -流程控制的使用
#五.流程控制的使用 #1.IF 使用 create PROCEDURE iftest1() BEGIN DECLARE a int DEFAULT 10; -- IF (a>1 &&a ...
- javascript总结46: JS三大系列-方便的offset 家族
1 offset 家族 offset这个单词本身是--偏移,补偿,位移的意思. js中有一套方便的获取元素尺寸的办法就是offset家族: 2 offset 结构介绍为: 3 offset常用属性 ...
- UVALive 7752 Free Figurines (瞎搞)
题意:给定 n 个盒子,然后告诉你每个盒子在哪个盒子里,数值越大,盒子越大,给定你初态,和末态,问你最少要几步能完成,只有两种操作,一种是把一个盒子连同里面的小盒子放到一个空盒子里,另一种是把一个堆盒 ...