对于小型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. 275. H-Index II 递增排序后的论文引用量

    [抄题]: Given an array of citations in ascending order (each citation is a non-negative integer) of a ...

  2. Python遍历一个文件夹下有几个Excel文件及每个Excel文件有几个Sheet

    一. 解决问题: 工作中常会遇到合并Excel文件的需求,Excel文件数量不确定,里面的Sheet 数量是可变的,Sheet Name是可变的,所以,需要用到遍历一个文件夹下有几个Excel文件,判 ...

  3. .net 多线程同步的相关知识点

    在多线程开发中,共享对象的同步是经常遇到的问题,以下总结了C#中线程同步的几种技术: 1,InterLocked原子操作 Decrement(ref int location);递减1 Add(ref ...

  4. sqlserver镜像相关资料

    本文出处:http://blog.csdn.net/dba_huangzj/article/details/35995083 镜像(Mirroring) SQL Server镜像简介 计划搭建SQL ...

  5. Openssl smime命令

    一.简介 S/MIME工具,用于处理S/MIME邮件,它能加密.解密.签名和验证S/MIME消息 二.语法 openssl smime [-encrypt] [-decrypt] [-sign] [- ...

  6. Spring Boot☞ 使用velocity渲染web视图

    效果图: 代码 <!DOCTYPE html><html><head lang="en"> <meta charset="UTF ...

  7. Win10安装Mongodb,并配置成服务

    好吧,今天突然发现新买的surface上没有安装mongodb,然后想着安装一下,顺便记录一下,虽说安装过程很简单 一:下载安装,然后拷贝到C盘根目录,这个就不多说了,比QQ都简单. 二:把bin文件 ...

  8. [GO]无缓冲通道(unbuffered channel)

    无缓冲通道(unbuffered channel)是指在接收前没有能力保存任何值的通道,在之前的例子中使用的都是无缓冲通道,需要注意的是,对于无缓冲通道而言,不管是往通道里写数据还是从通道里读数据,都 ...

  9. WordPaster-Joomla_3.4.7-tinymce 4.1.7示例发布

    资源下载:Joomla 3x,   1.1.1. 1.添加wordpaster文件夹 /media/   1.1.2. 2.添加插件文件夹 路径:media/editors/tinymce/plugi ...

  10. 设计模式8---适配器模式(Adapter)

    1. 适配器模式简介 适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用场景: 1.已经存在 ...