【Unity开发】数据存储——XML
一、相关介绍
1、XML介绍
XML,全称可拓展标记语言(EXtensible Markup Language),是被设计用于传输和存储数据的一种文本特殊格式。
2、优缺点
优点:格式统一,符合标准,容易与其他系统进行远程交互,数据共享比较方便。
缺点:XML文件庞大,文件格式复杂,传输占带宽;服务器端与客户端解析XML花费较多的资源和时间。
3、基本规则
①每个元素都必须有关闭标签
②元素命名规则基本遵照C#中变量名命名规则
③XML标签对大小写敏感
④XML文档必须有根元素
⑤特殊的符号应该用实体引用
4、XML属性
(1)属性语法
(2)属性和元素节点的区别(只有写法上的区别)
5、如何检查语法错误
①元素标签必须配对
②属性必须有引号
③注意命名
④将内容直接复制到该网站进行验证:https://www.runoob.com/xml/xml-validator.html
6、XML存放位置
①只读不写,存放在Resources或者StreamingAssets文件夹下
②动态存储,放在Application.persistentDataPath路径下
二、具体实现
1、常用功能实现
using System.Collections;using System.Collections.Generic;using System.IO;using System.Xml;using UnityEngine;public class LoadXml : MonoBehaviour{ // Start is called before the first frame update void Start() { #region 读取xml文件信息 //方法一、读取Resources文件夹下的xml文件加载处理 TextAsset textAsset = Resources.Load<TextAsset>(\"TestXml\"); print(textAsset.text); XmlDocument xml = new XmlDocument(); xml.LoadXml(textAsset.text); //方法二、读取StreamingAssets文件夹下的xml文件加载处理 //xml.Load(Application.streamingAssetsPath + \"/Testxml.xml\"); #endregion #region 读取元素和属性信息 //1、获取xml中的根节点 XmlNode root = xml.SelectSingleNode(\"Root\"); //2、通过根节点获取下面的字节点 XmlNode nodeName = root.SelectSingleNode(\"name\"); //3、获取节点包裹的元素信息 print(nodeName.InnerText); //4、获取节点属性信息 XmlNode nodeItem = root.SelectSingleNode(\"Item\"); //方式一 print(nodeItem.Attributes[\"id\"].Value); print(nodeItem.Attributes[\"num\"].Value); //方式二 print(nodeItem.Attributes.GetNamedItem(\"id\").Value); print(nodeItem.Attributes.GetNamedItem(\"num\").Value); //5、获取一个节点下的同名节点的方法 XmlNodeList friendList = root.SelectNodes(\"Friend\"); //遍历打印信息 //方法一、使用迭代器遍历 foreach (XmlNode item in friendList) { print(item.SelectSingleNode(\"name\").InnerText); print(item.SelectSingleNode(\"age\").InnerText); } //方法二、使用for循环遍历 for (int i = 0; i < friendList.Count; i++) { print(friendList[i].SelectSingleNode(\"name\").InnerText); print(friendList[i].SelectSingleNode(\"age\").InnerText); } #endregion #region 存储xml文件信息 //1、存储路径 //Resources 可读 不可写 打包后找不到 x //Application.streamingAssetsPath 可读 PC端可写 找得到 x //Application.dataPath 打包后找不到 x //Application.persistentDataPath 可读可写找得到 ✔ string path = Application.persistentDataPath + \"/PlayerInfo2.xml\"; print(path); //2、存储xml文件 //(1)创建文本对象 XmlDocument xml1 = new XmlDocument(); //(2)添加固定版本信息 XmlDeclaration xmlDec = xml1.CreateXmlDeclaration(\"1.0\", \"UTF-8\", \"\"); xml1.AppendChild(xmlDec); //(3)添加根节点 XmlElement root1 = xml1.CreateElement(\"Root\"); xml1.AppendChild(root1); //(4)为根节点添加子节点 XmlElement name = xml1.CreateElement(\"name\"); name.InnerText = \"某某某\"; root1.AppendChild(name); XmlElement listInt = xml1.CreateElement(\"int\"); for (int i = 0; i < 3; i++) { XmlElement childNode = xml1.CreateElement(\"int\"); childNode.InnerText = i.ToString(); listInt.AppendChild(childNode); } root1.AppendChild(listInt); //(5)添加属性 XmlElement itemList = xml1.CreateElement(\"itemList\"); for (int i = 0; i < 3; i++) { XmlElement childNode = xml1.CreateElement(\"Item\"); //添加属性 childNode.SetAttribute(\"id\", i.ToString()); childNode.SetAttribute(\"num\", (i * 10).ToString()); itemList.AppendChild(childNode); } root1.AppendChild(itemList); //(6)保存 xml1.Save(path); print(\"成功保存到文件夹:\" + path); #endregion #region 修改xml文件信息 //1、先判断是否存在文件 if (File.Exists(path)) { //2、加载后 直接添加节点 移除节点即可 XmlDocument xml2 = new XmlDocument(); xml2.Load(path); //移除 XmlNode node = xml2.SelectSingleNode(\"Root\").SelectSingleNode(\"name\"); node = xml2.SelectSingleNode(\"Root/name\"); print(node.InnerText); //得到自己的父节点 XmlNode root2 = xml2.SelectSingleNode(\"Root\"); root2.RemoveChild(node); //添加 XmlNode speed = xml2.CreateElement(\"moveSpeed\"); speed.InnerText = \"20\"; root.AppendChild(speed); //修改后 记得保存更新xml文件 xml2.Save(path); } #endregion }}
2、字典自定义序列化与反序列化实现
using System.Collections;using System.Collections.Generic;using System.Xml;using System.Xml.Schema;using System.Xml.Serialization;using UnityEngine;public class SerizlizerDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable{ public XmlSchema GetSchema() { return null; } //自定义字典的 反序列化 规则 public void ReadXml(XmlReader reader) { XmlSerializer keySer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSer = new XmlSerializer(typeof(TValue)); //要跳过根节点 reader.Read(); //判断 当前不是元素节点 结束 就进行 反序列化 while (reader.NodeType != XmlNodeType.EndElement) { //反序列化键 TKey key = (TKey)keySer.Deserialize(reader); //反序列化值 TValue value = (TValue)valueSer.Deserialize(reader); //存储到字典中 this.Add(key, value); } reader.Read(); } //自定义 字典的 序列化 规则 public void WriteXml(XmlWriter writer) { XmlSerializer keySer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSer = new XmlSerializer(typeof(TValue)); foreach (KeyValuePair<TKey, TValue> kv in this) { //键值对 的序列化 keySer.Serialize(writer, kv.Key); valueSer.Serialize(writer, kv.Value); } }}
3、XML存储与读取功能封装
using System;using System.Collections;using System.Collections.Generic;using System.IO;using System.Xml.Serialization;using UnityEngine;public class XmlDataMgr{ private static XmlDataMgr instance = new XmlDataMgr(); public static XmlDataMgr Instance => instance; private XmlDataMgr() { } /// /// 保存数据到xml文件中 /// /// 数据对象 /// 文件名 public void SaveData(object data, string fileName) { //1.得到存储路径 string path = Application.persistentDataPath + \"/\" + fileName + \".xml\"; //2.存储文件 using(StreamWriter writer = new StreamWriter(path)) { //3.序列化 XmlSerializer s = new XmlSerializer(data.GetType()); s.Serialize(writer, data); } } /// /// 从xml文件中读取内容 /// /// 对象类型 /// 文件名 /// public object LoadData(Type type, string fileName) { //1。首先要判断文件是否存在 string path = Application.persistentDataPath + \"/\" + fileName + \".xml\"; if( !File.Exists(path) ) { path = Application.streamingAssetsPath + \"/\" + fileName + \".xml\"; if (!File.Exists(path)) { //如果根本不存在文件 两个路径都找过了 //那么直接new 一个对象 返回给外部 无非 里面都是默认值 return Activator.CreateInstance(type); } } //2.存在就读取 using (StreamReader reader = new StreamReader(path)) { //3.反序列化 取出数据 XmlSerializer s = new XmlSerializer(type); return s.Deserialize(reader); } } }