XML数据持久化学习笔记
一.XML基础语法
1.XML结构:XML是一种树结构的文本
2.XML注释:格式:<!--在其中书写注释-->,在注释中可以单行注释也可以多行注释
3.固定内容:<?xml version="1.0" encoding="UTF-8"?>版本和编码信息
4.基本语法:<root>...</root>,一个节点的内容使用尖括号包裹节点名称开始,尖括号包裹斜杠和节点名称结束,子节点的内容被包裹在这两个尖括号中间。通过在最下层的子节点的首尾尖括号之间包裹数据的形式保存数据。这种节点的树形结构和对象这种引用类型中包含值类型(没有子节点)和其他引用类型(有子节点)的形式是一致的。
5.属性:和元素节点只是写法上的区别,相当于简化的节点写法
1)<Father name="爸爸" age="52">...</Father>
2)<Father name="爸爸" age="52"/>
二.Unity中XML的存放位置
1.Resources 只读文件,打包后找不到
2.Application.streamingAssetsPath 可读,PC端可写,能找到
3.Application.dataPath 打包后找不到
4.Application.persistentDataPath 可读可写能找到
三.Unity中读取xml文件信息
1.常见的读取方式
1)XmlDocument:把数据加载到内存中,方便读取
2)XmlTextReader:以流形式加载数据,内存占用更少,但是单向只读
3)Linq
2.使用XmlDocument读取和存储信息的一些方法
1)LoadXml成员方法:将字符串加载到xml中
2)Load成员方法:将路径对应的xml文件的内容加载到xml中
3)SelectSingleNode成员方法:得到单个节点,存储为XmlNode对象,XmlNode中同样有这个成员方法得到节点的单个子节点
4)节点对象.Attributes[属性名].Value得到属性值,或者节点对象.Attributes.GetNamedItem(属性名).Value可以达到同样的效果
5)SelectNodes成员方法:得到节点下的所有同名节点,存储为XmlNodeList对象
6)CreateXmlDeclaration成员方法:创建固定版本和编码信息
7)AppendChild:把节点对象添加到xml中
8)CreateElement:创建节点
9)InnerText属性:节点中存储的信息
10)SetAttribute成员方法:添加属性
11)Save成员方法:保存
3.使用XmlDocument读取和存储信息的一些重要类
1)XmlNode:读取出的单个节点信息类
2)XmlNodeList:读取出的多个同名节点信息类存储到一个list中
3)XmlElement:存储时的单个节点信息类
4)XmlDeclaration:存储时创建出的xml文件固定版本和编码等信息类
四.xml序列化和通用保存加载类
1.xml序列化
1)序列化:把对象转化为可传输的字节序列过程称为序列化
反序列化:将字节序列还原为对象的过程称为反序列化
2)using关键字:using关键字的格式和if类似,都是在后面跟上一个小括号和一个大括号。using关键字后面的小括号中的内容一般是声明一个对象,这个对象需要是继承IDispose接口的对象,在大括号中的代码块调用完毕后,系统会自动调用小括号中对象的Dispose方法将对象释放。一般用于内存占用较大或者读写时操作。
3)序列化类XmlSerializer和输出流StreamWriter:序列化类的对象相当于一个翻译机器,负责将对象进行序列化翻译,而输出流的对象相当于传送带,负责传输序列化前后的信息。因此,new一个XmlSerializer类对象时需要指定类型(翻译的类的类型),而new一个StreamWriter类对象时需要指定文件地址(传动带的终点),“输入”或者“输出”相当于是说的传送方向(传送带是单向的);使用Serialize方法进行序列化翻译时需要指定流对象(传送带)和要序列化的对象。
4)示例:
TestClass test = new TestClass();
string path = Application.persistentDataPath + "/TestClass.xml"; //尝试创建一个文件流,需要指定文件地址,会自动打开文件(如果有文件直接打开,如果没有文件自动新建一个文件再打开)
//using括号中声明的对象会在大括号中语句块结束后自动释放
//using在语句块结束后自动调用对象的Dispose方法(继承IDispose接口),让对象自行销毁
//一般在内存占用较大或者有读写操作时使用
using(StreamWriter stream = new StreamWriter(path))
{
//序列化对象相当于翻译机器,将对象翻译为序列化文件,需要指定机器能翻译的对象的类型;流相当于传送带,负责运输翻译的对象和结果
//创建序列化对象,需要指定这个序列化对象的类型
XmlSerializer xs = new XmlSerializer(typeof(TestClass));
//调用序列化对象的Serialize方法将对象test通过stream流序列化
xs.Serialize(stream,test);
}
进行序列化的代码。
public class TestClass
{
public int testPublic = 1;
private int testPrivate = 2;
protected int testProtected = 3;
internal int testInternal = 4; public string testStrPublic = "12";
public int testPro { get; set; } public TestClass2 testClass = new TestClass2(); } public class TestClass2
{
public int test1 = 1;
public float test2 = 2.2f;
public bool test3 = false;
}
被序列化的对象的模板类。
<?xml version="1.0" encoding="utf-8"?>
<TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<testPublic>1</testPublic>
<testStrPublic>12</testStrPublic>
<testClass>
<test1>1</test1>
<test2>2.2</test2>
<test3>false</test3>
</testClass>
<testPro>0</testPro>
</TestClass>
序列化出来的xml文件内容,可以看到只有public的属性和变量被存储下来了。
注意:这种序列化方式支持数组、list等,但是不支持dictionary。
5)使用特性为序列化进行自定义
[XmlAttribute()]:在类中的属性或变量上加上这个特性,这个属性或变量在序列化时会存储为属性,可以在括号中指定自定义属性名称
[XmlElement()]:在类中的属性或变量上加上这个特性,这个属性或变量在序列化时存储为节点(默认也是存储为节点),可以在括号中指定自定义节点名称
[XmlArrayItem()]:在类中的数组属性(变量)前加上这个特性,在括号内传入自定义数组的元素存储为的节点名称
[XmlArray()]:在类中的list属性(变量)前加上这个特性,在括号内传入自定义的list的元素存储为的节点名称
2.xml反序列化
序列化和反序列化的方法是一一对应的,把序列化过程反过来就可以,示例:
string path = Application.persistentDataPath + "/TestClass.xml";
TestClass test1 = null;
using (StreamReader stream = new StreamReader(path))
{
XmlSerializer xs = new XmlSerializer(typeof(TestClass));
test1 = (TestClass)xs.Deserialize(stream);
}
注意:在反序列化时,如果类中声明变量时list类型的变量有默认值,会调用add方法往list中添加值,也就是说反序列化后默认值和反序列化的值都会存储在list变量中,因此尽量不要在创建对象时为list赋初值。
3.IXmlSerializable接口
继承IXmlSerializable接口能够自定义类的序列化和反序列化。继承后需要重写方法:
/// <summary>
/// 返回结构
/// </summary>
/// <returns></returns>
public XmlSchema GetSchema()
{
return null;
} /// <summary>
/// 反序列化时自动调用的方法
/// </summary>
/// <param name="reader"></param>
public void ReadXml(XmlReader reader)
{
//读属性
this.testStrPublic = reader["testStrPublic"]; //读节点
//方式一:
//每次reader读取一块内容(一个尖括号的内容或者尖括号包裹的信息),先读取节点开始的尖括号,再读取节点中的内容,再read就继续读取节点结束的尖括号
reader.Read();
reader.Read();
this.testPublic = int.Parse(reader.Value);
//方式二:
//循环读取
while (reader.Read())
{
//判断读取出的类型,是节点开始标签(XmlNodeType.Element)、节点中包裹的内容(XmlNodeType.Text)还是节点结束标签(XmlNodeType.EndElement),根据读取出的类型作处理
if (reader.NodeType == XmlNodeType.Text)
{
//Name属性是节点的名称,根据节点名称作响应的处理
switch (reader.Name)
{
case "testPublic":
break;
}
}
} //读包裹节点
XmlSerializer xs = new XmlSerializer(this.testStrPublic.GetType());
//跳过根节点
reader.Read();
reader.ReadStartElement("testStrPublic");
this.testStrPublic = (string)xs.Deserialize(reader);
reader.ReadEndElement();
} /// <summary>
/// 序列化时自动调用的方法
/// </summary>
/// <param name="writer"></param>
public void WriteXml(XmlWriter writer)
{
//写属性
writer.WriteAttributeString("testStrPublic", this.testStrPublic); //写节点
writer.WriteElementString("testStrPublic", this.testStrPublic); //写包裹节点
writer.WriteStartElement("testStrPublic");
XmlSerializer xs = new XmlSerializer(this.testStrPublic.GetType());
xs.Serialize(writer,this.testStrPublic);
writer.WriteEndElement();
}
4.让Dictionary支持xml序列化和反序列化
只需要重写一个继承Dictionary的类,这个类再实现IXmlSerializable接口,重写方法即可。
public class SerializerDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
public XmlSchema GetSchema()
{
return null;
} public void ReadXml(XmlReader reader)
{
XmlSerializer keyXS = new XmlSerializer(typeof(TKey));
XmlSerializer valueXS = new XmlSerializer(typeof(TValue));
//跳过根节点
reader.Read();
//没有到根节点的结束尖括号,就可以一直读取
while(reader.NodeType != XmlNodeType.EndElement)
{
TKey key = (TKey)keyXS.Deserialize(reader);
TValue value = (TValue)valueXS.Deserialize(reader);
this.Add(key, value);
}
} public void WriteXml(XmlWriter writer)
{
XmlSerializer keyXS = new XmlSerializer(typeof(TKey));
XmlSerializer valueXS = new XmlSerializer(typeof(TValue));
foreach(KeyValuePair<TKey,TValue> pair in this)
{
keyXS.Serialize(writer, pair.Key);
valueXS.Serialize(writer, pair.Value);
}
}
}
5.xml管理类
public class XmlDataManager
{
//单例模式模块
private static XmlDataManager instance;
public static XmlDataManager Instance
{
get
{
if (instance == null)
instance = new XmlDataManager();
return instance;
}
}
private XmlDataManager() { } /// <summary>
/// 数据存储类
/// </summary>
/// <param name="data">存储的数据对象</param>
/// <param name="fileName">文件名</param>
public void SaveData(object data,string fileName)
{
string path = Application.persistentDataPath + "/" + fileName + ".xml";
using(StreamWriter writer = new StreamWriter(path))
{
XmlSerializer xs = new XmlSerializer(data.GetType());
xs.Serialize(writer, data);
}
} /// <summary>
/// 加载对象
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="fileName">文件名称</param>
/// <returns></returns>
public object LoadData(Type type,string fileName)
{
string path = Application.persistentDataPath + "/" + fileName + ".xml";
if (!File.Exists(path))
{
path = Application.persistentDataPath + "/" + fileName + ".xml";
if (!File.Exists(path))
{
return Activator.CreateInstance(type);
}
}
object result = null;
using(StreamReader reader = new StreamReader(path))
{
XmlSerializer xs = new XmlSerializer(type);
result = xs.Deserialize(reader);
}
return result;
}
}
XML数据持久化学习笔记的更多相关文章
- Java EE数据持久化框架笔记 • 【目录】
章节 内容 实践练习 Java EE数据持久化框架作业目录(作业笔记) 第1章 Java EE数据持久化框架笔记 • [第1章 MyBatis入门] 第2章 Java EE数据持久化框架笔记 • [第 ...
- 大数据 -- kafka学习笔记:知识点整理(部分转载)
一 为什么需要消息系统 1.解耦 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束. 2.冗余 消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险.许多 ...
- tensorflow拟合随机生成的三维数据【学习笔记】
平台信息:PC:ubuntu18.04.i5.anaconda2.cuda9.0.cudnn7.0.5.tensorflow1.10.GTX1060 作者:庄泽彬(欢迎转载,请注明作者) 说明:感谢t ...
- XSD(XML Schema Definition)学习笔记
今天学习了XSD相关的知识,为了以后查找的方便,写一些笔记. 一.什么是XSD? 1.XSD全称:XML Schema Definition.XML Schema 的作用是定义 XML 文档的合法构建 ...
- Web客户端数据存储学习笔记——Cookie
今天对登录访问的安全以及web客户端存储做了一些大致的学习,决定在这方面加深理解,记录在博客里.第一个接触到的是Cookie... WHAT? WHY? HOW? 在学习cookie的使用时发现其名称 ...
- EF code First数据迁移学习笔记(转)
转自:http://www.cnblogs.com/icyJ/p/migration.html 准备工作 1.新建一个控制台项目, 在"程序包管理控制台"执行 Install-pa ...
- 通过程序校验xml文档学习笔记
校验xml文档,可以通过程序来校验,利用一段js代码即可. 各行代码的含义已经写出,运行这个html文件,检验如下xml代码: 结果如下: 如果xml文档出现错误: 结果如下: 其中,obj.asyn ...
- SuperMap 9D 实时数据服务学习笔记
SuperMap 在9月份发布了结合大数据技术的9D新产品,今天就和大家介绍下iServer9D中的实时数据服务. 1.技术框架 结合Spark的streaming流处理框架,将各种数据进行批量处理. ...
- EF code First数据迁移学习笔记
准备工作 1.新建一个控制台项目, 在"程序包管理控制台"执行 Install-package EntityFramework //安装EF环境 2.在项目下新建类(Paper) ...
随机推荐
- css animation & animation-fill-mode
css animation & animation-fill-mode css animation effect https://developer.mozilla.org/en-US/doc ...
- Electron in Action
Electron in Action $ yarn add -D electron@latest # OR $ npm i -D electron@latest https://www.electro ...
- API 注解 & Java API annotation
API 注解 & Java API annotation 注解 annotation
- ROS1与ROS2对比简述
资料参考: https://blog.csdn.net/Fourier_Legend/article/details/106319000
- c/c++ 之静态库
静态库 编译成目标文件(未链接) g++ -c a.cc b.cc c.cc d.cc #生成 a.o b.o c.o d.o 将目标文件打包为静态库 ar rs libxxx.a a.o b.o c ...
- 【Android初级】如何实现一个有动画效果的自定义下拉菜单
我们在购物APP里面设置收货地址时,都会有让我们选择省份及城市的下拉菜单项.今天我将使用Android原生的 Spinner 控件来实现一个自定义的下拉菜单功能,并配上一个透明渐变动画效果. 要实现的 ...
- Excel小技巧之VLOOKUP()使用简单说明
前两天人事的小姐姐需要处理一个表格,需要在一张新表中的匹配旧表的数据,由于数据量较大不知如何处理. 我告诉她使用VLOOKUP()函数,然后她不知道怎么使用.其实我也不大用,因为数据库用的多很少使用表 ...
- Python Linux 命令行执行脚本输出重定向print到日志文件
reference: https://unix.stackexchange.com/questions/182537/write-python-stdout-to-file-immediately ...
- 渗透测试--Nmap主机识别
通过本篇博客可以学到:Nmap的安装和使用,列举远程机器服务端口,识别目标机器上的服务,指纹,发现局域网中存活主机,端口探测技巧,NSE脚本使用,使用特定网卡进行检测,对比扫描结果ndiff,可视化N ...
- hexo 报错 use_date_for_updated is deprecated...
hexo 报错 use_date_for_updated is deprecated... WARN Deprecated config detected: "use_date_for_up ...