xmlreader与xmlwriter里的几个坑与解决方案
加载超过100M的xml文件时(可能不是很常见),XmlDocument这种全部加载到内存里的模式就有点不友好了,耗时长、内存高。
这时用xmlreader就会有自行车换超跑的感觉,但其间遇到几个坑,记录一下。
先看源码,包括dom和sax两种模式的读取和写入
DOM模式:
1 /// <summary>
2 /// dom模式创建xml文件
3 /// </summary>
4 /// <param name="path"></param>
5 public void CreateXml_Dom(string path)
6 {
7 XmlDocument xmlDocw = new XmlDocument();
8 //xml头
9 var xmldecl = xmlDocw.CreateXmlDeclaration("1.0", "utf-8", null);
10 var root = xmlDocw.CreateElement("root");
11 root.SetAttribute("Name", "李四");
12 var test = xmlDocw.CreateElement("test");
13 root.AppendChild(test);
14
15 xmlDocw.AppendChild(xmldecl);
16 xmlDocw.AppendChild(root);
17 xmlDocw.Save(path);
18
19 //可以通过xmlreader读数据后生成节点
20 //var node = xmlDocw.ReadNode(rdr);
21 //root.AppendChild(node);
22 //或者读取outerxml后作为innerxml写入
23 //string str = rdr.ReadOuterXml();
24 //root.InnerXml = str;
25 }
26
27 /// <summary>
28 /// dom模式读取xml
29 /// </summary>
30 /// <param name="path"></param>
31 public void ReadXml_Dom(string path)
32 {
33 XmlDocument xmlDocr = new XmlDocument();
34 xmlDocr.Load(path);
35 var root = xmlDocr.DocumentElement;
36 string str = root.GetAttribute("Name");
37 Console.WriteLine(str);
38 }
SAX(simple API for XML)模式:几种错误也都用注释标注出来了
1 /// <summary>
2 /// xmlwriter创建xml文件
3 /// </summary>
4 /// <param name="path"></param>
5 public void CreateXml_Sax(string path)
6 {
7 //filestream没问题
8 //FileStream stream = new FileStream(path,FileMode.Create);
9 //会出现编码一直是utf-16问题
10 //StringBuilder stream = new StringBuilder();
11 MemoryStream stream = new MemoryStream();
12 XmlWriterSettings settings = new XmlWriterSettings();
13 //Encoding.UTF8这个会报错,字节顺序标记
14 settings.Encoding = new UTF8Encoding(false);
15 XmlWriter xw = XmlWriter.Create(stream, settings);
16 //XmlTextWriter xw = new XmlTextWriter(stream, new UTF8Encoding(false));
17
18 //写入声明
19 xw.WriteStartDocument();
20
21 xw.WriteStartElement("root");
22 xw.WriteAttributeString("Name", "张三");
23 //可以通过xmlreader读数据后直接写入
24 //xw.WriteNode(rdr);
25 xw.WriteStartElement("test");
26 xw.WriteEndElement();
27
28 xw.WriteEndElement();
29
30 xw.WriteEndDocument();
31 xw.Close();
32
33 string xmlstr = Encoding.UTF8.GetString(stream.ToArray());
34 stream.Close();
35 XmlDocument xmlDocw = new XmlDocument();
36 xmlDocw.LoadXml(xmlstr);
37 xmlDocw.Save(path);
38 }
39
40 /// <summary>
41 /// xmlreader读取xml
42 /// </summary>
43 /// <param name="path"></param>
44 public void ReadXml_Sax(string path)
45 {
46 XmlDocument xmlDocw = new XmlDocument();
47 XmlReaderSettings rsettings = new XmlReaderSettings();
48 rsettings.IgnoreComments = true;
49 rsettings.IgnoreWhitespace = false;
50 rsettings.CheckCharacters = false;
51 //默认的xmlreader不读取内容中的回车换行\r\n
52 //(XmlReader rdr = XmlReader.Create(path,rsettings))
53 using (XmlTextReader rdr = new XmlTextReader(path))
54 {
55 rdr.WhitespaceHandling = WhitespaceHandling.Significant;
56 string eleName = "";
57 while (rdr.Read())
58 {
59 if (rdr.NodeType == XmlNodeType.Element)
60 {
61 //节点名称
62 eleName = rdr.Name;
63 //节点深度
64 int dp = rdr.Depth;
65 //是否空节点,表示<elememt/> 不是<element></element>
66 bool needend = rdr.IsEmptyElement;
67 for (int i = 0; i < rdr.AttributeCount; i++)
68 {
69 rdr.MoveToAttribute(i);
70 Console.WriteLine(rdr.Name+":"+rdr.Value);
71 }
72 //可以直接读取节点所有的数据.可以用readNode读取
73 //rdr.EOF判定,不然会跳过节点
74 //rdr.ReadOuterXml();
75 }
76 else if (rdr.NodeType == XmlNodeType.EndElement)
77 {
78 eleName = rdr.Name;
79 }
80 }
81 }
82 }
xmlreader和xmldocument(xmlwriter)组合一起用对大型xml进行拆分读取,十分有效。
下面是遇到的问题:
1.xmlwriter后xml文件头始终是utf-16

这是用StringBuilder才会有的问题,改用FileStream、MemoryStream等就好了。
2.(UTF8)改用MemoryStream后,形成的xml字符串通过XMLDocument.LoadXml时报错
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;

最终发现默认的Encoding.UTF8是带有字节顺序标记的,要用new UTF8Encoding(false);
通过监视区代码可以看到,xmlstr[0]是65279,修改后就对了变成60'<'。


3.xmlreader默认不读取内容中的回车换行,读进来就是个空格。

第二个直接回车换行就是读不进来,用xmldocument可以读到两个,xmlreader就是读取不到。

期间一直在找设置,比如IgnoreWhitespace等,发现都没有用,还是不读。
XmlReaderSettings rsettings = new XmlReaderSettings();
rsettings.IgnoreWhitespace = false;
最后在stackoverflow上找到答案(注1),不能用XmlReader rdr = XmlReader.Create(path),用XmlTextReader就好了。

注1:不读回车换行问题 https://stackoverflow.com/questions/1793908/xmlreader-newline-n-instead-of-r-n
This is because the XmlTextReader has a normalization setting defaulted to false unlike XmlReader.Create which always normalizes newlines no matter what.
本文为原创,转载请注明:https://www.cnblogs.com/zhanglb163/
xmlreader与xmlwriter里的几个坑与解决方案的更多相关文章
- C#操作XMl文件(2):使用XmlReader和XmlWriter实现读取和写入
这次使用操作Xml较为常用的方法:使用XMlreader和Xmlwriter 1:读取xml文件的数学和元素 XmlReaderSettings settings = new XmlReaderSet ...
- 36、XmlReader与 XMLWriter(抽象类)
一.概述 XMLReader为抽象类,其派生类有:XmlDictionaryReader.XmlNodeReader.XmlTextReader(与IO命名空间中的TextReader对象一起使用). ...
- 第七篇 -- XmlReader 和 XmlWriter
XmlReader用于读取Xml文件,XmlWriter用于将数据写到Xml文件.其实,在印象当中,XML很多的操作类都支持直接Save.Read也支持接受XmlReader与XmlWriter类的示 ...
- 安装CentOS 7.4 可能会出现的坑以及解决方案
安装CentOS 7.4 可能会出现的坑以及解决方案 (解决方法不唯一,如果行不通的话emmmm~~, 百度会啥你会啥~~) 坑.0X01 解决: 退出虚拟机,以管理员权限运行 坑.0X02 解决: ...
- 使用appium过程中常遇到的坑以及解决方案
立志踩遍所有的坑...以下是学appium遇到的坑以及解决方案,方便自己的同时,也方便他人. 一.cmd输入:aapt dump badging C:\Users\XX\Desktop\xxx.apk ...
- 关于parseInt()里的一些小坑
parseInt(string,radix)方法是将输入字符串转化为数值,两个输入参数中string为要转化的字符串,radix可省略,是浏览器以几进制来解读输入的string. 举几个例子就能够对该 ...
- 在centos服务器里安装opencv的坑:mportError: libXrender.so.1: cannot open shared object file: No such file or directory and wrong ELF class: ELFCLASS32
centos7服务器安装opencv (其他版本服务器一样) 安装opencv: pip install opencv-python 导入cv2 import cv2 报错:importError: ...
- ajax传参里含有特殊字符的坑
问题场景:今天在测试自己手上的页面功能时,发现一个小bug,在用ajax向后台发数据时,只要参数中出现一些特殊字符,控制台会报错http 400的问题,其实就是特殊字符服务器不能解析.好了,问题是找到 ...
- 曾经的pc端项目踩到的一些兼容性的坑及其解决方案
曾经公司pc端项目一直最低兼容到IE7,要求和chrome下浏览效果一致,真心坑坏了我和另外一个小伙伴(另一个小伙伴以前也没处理过兼容问题).不过还好,在这里真心感谢鑫哥博客的详解,从底层原理讲到了具 ...
随机推荐
- AngularJS:Select
ylbtech-AngularJS:Select 1.返回顶部 1. AngularJS Select(选择框) AngularJS 可以使用数组或对象创建一个下拉列表选项. 使用 ng-option ...
- php代码中临时开启错误调试
对php.ini 中参数的设置 也可用在php代码中完成. 调用:调用ini_set()函数 //开启php.ini中的display_errors指令 ini_set('display_errors ...
- 4.solr学习速成之bean
以bean的形式提交索引,以bean的形式查询出来 package com.liucheng.solr; import java.io.Serializable; import org.apache. ...
- Python 中的进程与 锁
理论知识 操作系统背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操 ...
- 03-CSS中的选择器
高级选择器分为: 后代选择器 子代选择器 并集选择器 交集选择器 后代选择器 使用空格表示后代选择器 , 顾名思义 父元素的后代(包括儿子,孙子,重孙子) 中间空格隔开 是后代 .container ...
- Android 从本地图库或拍照后裁剪图片并设置头像
在QQ和微信等应用都会有设置头像,一般都是从本地图库选取或相机拍照,然后再截图自己喜欢的部分,然后设置.最后一步把截取好的图片再保存到本地,来保存头像.为了大家使用方便,我把自己完整的代码贴出来,大家 ...
- STM32与PC机串口通讯
有时要将板子的信息输出到电脑上来调试之类的,或者把传感器收集到的数据显示到电脑. 当然了,这只是最基本的串口通信,简单的说,是有一根USB线连着的. mbed上并没有能显示printf的功能.需要自己 ...
- SqlConnection 无法设置连接超时
1.最有效的方法:对表格建立索引 2 在连接字符串中设置 Connection Timeout (默认15秒)3 设置 SqlCommand.CommandTimeout(默认是 30 秒)
- 如何解决quartz在集群下出现的资源抢夺现象
Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中.它提供了巨大的灵活性而不牺牲简单性.你能够用它来为执行一个作业而创建简单的或复杂的调度,简单的说就是可以 ...
- 25-从零玩转JavaWeb-抽象类
一.抽象类解决什么问题 求三角形,圆,矩形的面积 发现三个类都有共同的方法 ,所以我们可以抽出一个父类, 把他们相同的方法放到父类当中 二.什么是抽象方法 三.什么是抽象类 四.抽象类的特 ...