数据持久化-XML
Contents
XML
格式
<?xml version="1.0" encoding="UTF-8"?>
<Test>测试</Test>规则
- 每个元素都必须有关闭标签
- 元素命名规则 基本遵循C#中文变量名命名规则
- XML标签对大小写敏感
- XML为胆囊必须带有根元素
- 特殊符号应该用实体引用
- < 小于号
- &gl 大于号
- &aml &符号
- &apos 单引号
- " 引号
属性
<Item>
<id>1</id>
<num>2</num>
</Item>
<!-- 属性的写法-->
<Item id="1" num="10"/>Xml文件的存放位置
- 只读不写的xml文件 可以放在Resources或者StreamingAssets文件夹下
- 动态存储的xml文件可以放在Application.persistenDataPath路径下
C#读取xml的方式
- XmlDocument把数据加载到内存中方便读取
- XMLTextReader 以流形式加载 占用内存更少 但是单向只读 一般不会使用
- Linq
XmlDocument读取xml文件信息
加载xml文件
XmlDocument xml = new XmlDocument();
TextAsset asset = Resources.Load<TextAsset>("TestXml");
xml.LoadXml(text.text);
//通过路径来加载xml 不可以加载resources文件夹下面的
xml.load(Application.persistenDataPath+"TestXml.xml");读取xml文件
//通过XmlDocument对象 得到XmlNode 传入根节点
XmlNode root = xml.SelectSingleNode("Root");
//在通过根节点的对象 找到下面的子节点
XmlNode name = root.SelectSingleNode("name");
//获取内容
print(name.InnerText);
//获取属性
XmlNode item = root.SelectSingleNode("item");
print(item.Attributes["id"].Value);
//第二种方式
print(item.Attributes.GetNamedItem("id").Value);
//找到所有的xmlnode
XmlNodeList nodelist = xml.SelectNodes("Root");存储Xml文件
- 存储Xml文件 在Unity中一定是使用各平台都可读可写可找到的路径
- Resources 可读 但是不可写 打包后找不到
- Application.streamingAssetsPath 可读 Pc可写 可找到
- Application.dataPath 打包后找不到
- Application.persistentDataPath 可读可写找得到
关键类
- XmlDocument 用于创建节点 存储文件
- XmlDeclaration用于添加版本信息
- XmlElement 节点类
创建xml
//创建文本对象
XmlDocument xml = new XmlDocument();
//创建xml 版本信息
XmlDeclaration xmlDec = xml.CreateXmlDeclaration("1.0","UTF-8","");
//将版本信息添加到xml中
xml.AppendChild(xmlDec);
//添加根节点
XmlElment root = xml.CreateElement("Root");
xml.AppendChild(root);
//为根节点添加子节点 <name>路飞</name>
XmlElement name = xml.CreateElement("name");
name.InnerTest = "路飞";
//将name添加到root节点中
root.AppendChild(name);保存xml
xml.Save("路径");修改xml
//判断文件是否存在
if(File.Exists(path)){
//创建xml文本对象
XmlDocument xml = new XmlDocument();
xml.load(path);
//修改 就是在原有文件的基础上 删除 或者添加
XmlNode root = xml.SelectSingleNode("Root");
XmlNode node = root.SelectSingleNode("name");
XmlNode node2 = xml.SelectSingleNode("Root/name");//第二种写法
//移除节点
root.RemoveChild(node);
XmlElement name = xml.CreateElement("name");
name.InnerTest = "王路飞";
root.AppendChild(name);
//保存
xml.Save(path);
}XML序列化
using关键字
- using关键字 一般是配合 内存占用较大 或者又读写操作时 使用的
- using关键字 将会在大括号内代码执行完毕后 自动释放掉小括号中的对象
- 可以理解为是一种语法糖
using(){
}创建文件写入流
//首先确认存储的路径
string path = Application.persistentDataPath+"/Test.xml";
//创建文件写入流
StreamWriter stream = new StreamWriter(path)XmlSerializer用于序列化对象为xml的关键类
- 构造函数需要传入一个Type类型的参数
- 这种方式只可以 保存公共的成员
- 默认不可以序列化字典
XmlSerializer xs = new XmlSerializer(type);
//序列化
s.Serialize(文件流对象,对象);可通过添加特性 使字段实例化成xml的属性 还可以修改名字
public class Test {
[XmlAttribute("名字")]//把name序列化成属性 字段名是名字
public string name;
[XmlElement("年龄")]//把age序列化成节点 字段名是年龄
public int age;
public bool sex;
//修改数组的节点名字
[XmlArray("IntList")]
//修改数组内容的节点名字
[XmlArrayItem("Int32")]
public List<int> listInt;
}XML反序列化
判断路径是否存在
string path = Application.persistentDataPath + "/Test.xml";
//判断文件是否存在 传入路径
if(File.Exists(path)){
}反序列化
- 反序列化list 不会覆盖掉list原来的值 而是会在原有的基础上添加
//文件读取流
using(StreamReader stream = new StreamReader(path)){
XmlSerializer xs = new XmlSerializer(Typeof(Test));
Test test = xs.Deserialize(stream) as Test;
}IXmlSerializable接口
- 可以通过继承此接口 来重写序列化和反序列化的方法 从而实现序列化字典等等功能
- 要在接口中重写所有字段的 序列化或反序列化规则
- GetSchema返回null就可以了
- 写属性和读属性的规则要一致
public class Test : IXmlSerializable
{
public string name;
public int age;
public bool sex;
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
//读取属性 传入name中
name = reader["name"];
//读取
reader.Read();//读节点
reader.Read();//读节点的内容
//拿到节点的value
age = int.Parse(reader.Value);
//通过循环读取
while (reader.Read())
{
//如果读取到节点
if (reader.NodeType == XmlNodeType.Element) {
switch (reader.Name)
{
case "age":
reader.Read();//读到属性内的值
age = int.Parse(reader.Value);
break;
}
}
}
//跳过根节点
reader.Read();
reader.ReadStartElement("age");
reader.Read();//读节点内容
age = int.Parse(reader.Value);
reader.ReadEndElement();
XmlSerializer xs = new XmlSerializer(typeof(string));
reader.ReadStartElement("name");
name = xs.Deserialize(reader).ToString();
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
//写入属性 参数 属性名 内容
writer.WriteAttributeString("name", name);
//写入 节点
writer.WriteElementString("age", age.ToString());
//写子节点
writer.WriteStartElement("age");
writer.WriteStartElement("int", 300.ToString());
writer.WriteEndElement();
//可以使用这个类型原来的序列化方法
XmlSerializer xs = new XmlSerializer(typeof(string));
writer.WriteStartElement("age");
xs.Serialize(writer, name);
writer.WriteEndElement();
}
}创建自定义字典类使其可以序列化
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using UnityEngine;
public class MyDic<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) {
var key = keyxs.Deserialize(reader);
var value = valuexs.Deserialize(reader);
Add((TKey)key,(TValue)value);
}
reader.Read();//跳过尾节点
}
public void WriteXml(XmlWriter writer)
{
XmlSerializer keyxs = new XmlSerializer(typeof(TKey));
XmlSerializer valuexs = new XmlSerializer(typeof(TValue));
foreach (var item in this)
{
keyxs.Serialize(writer, item.Key);
valuexs.Serialize(writer, item.Value);
}
}
}