做盗版视频网站,wordpress获取文章的标签,网站关键字字数,小程序商城开发华网天下优秀目录 数据持久化XML概述XML文件格式XML基本语法XML属性 C#读取存储XMLXML文件存放位置C#读取XML文件C#存储XML文件 实践小项目必备知识点XML序列化#xff08;不支持字典#xff09;XML反序列化IXmlSerializable接口让Dictionary支持序列化反序列化 数据持久化XML概述
什么是… 目录 数据持久化XML概述XML文件格式XML基本语法XML属性 C#读取存储XMLXML文件存放位置C#读取XML文件C#存储XML文件 实践小项目必备知识点XML序列化不支持字典XML反序列化IXmlSerializable接口让Dictionary支持序列化反序列化 数据持久化XML概述
什么是数据持久化 数据持久化就是将内存中的数据模型转换为存储模型,以及 将存储模型转换为内存中的数据模型的统称
说人话:将游戏数据存储到硬盘,硬盘中数据读取到游戏 中,也就是传统意义上的存盘
XML是什么 全称:可拓展标记语言(EXtensible Markup Language) XML是国际通用的 它是被设计来用于传输和存储数据的一种文本特殊格式 文件后缀一般为.xml 如何理解不同后缀的文件
文件后缀名决定了文件的格式 不同的软件可以根据后缀名用来判断文件的类型 并且在打开文件时以特定的读取规则去解析它
文件后缀名是人为定的规则 可以有无数种,可以自定义 我们一般使用XML文件来记录和传输数据 XML文档就是使用XML格式配置填写的文档 后缀一般为.xml 我们在游戏中可以把游戏数据按照XML的格式标准 存储在XML文档中,再将XML文档存储在硬盘上或者传输给远端 达到数据持久化的目的
XML文件格式
XML基本语法
推荐xml文本编辑器
只要能打开文档的软件都能打开XML文件 常用的一些打开XML文件的方式 1.系统自带 – 记事本、写字板 2.专用XML文本编辑器 – XMLSpear、STDU XML Editor等等 3.通用文本编辑器 – Sublime Text等等 创建XML文件
直接右键创建文本,后缀改为xml 选择自己喜欢的用于编辑xml的软件 进行文本编辑 注释
!----
!--在其中写明注释内容--固定内容 固定内容代表xml的版本 使用的编码
?xml version1.0 encodingUTF-8?基本语法
!-- xm1的基本语法 就是元素标签/元素标签配对出现 --
PlayerInfoname唐老狮/nameage18/agesextrue/sexItemListItemid1/idnum10/num/ItemItemid2/idnum10/num/Item/ItemList
/PlayerInfo基本规则
1.每个元素都必须有关闭标签 2.元素命名规则基本遵照C#中变量名命名规则 3.XML标签对大小写敏感 4.XML文档必须有根元素 5.特殊的符号应该用实体引用 lt —— 小于 gt —— 大于 amp——和号 apos——单引号 quot——“引号
XML属性
!-- 属性就是在元素标签后面空格 添加的内容 --
!-- 注意:属性必须用引号包裹 单引号双引号都可以 --
Friend name小明”age8我的朋友/Friend
!-- 如果使用属性记录信息 不想使用元素记录 可以如下这样写 --
Fater name 爸爸”age 50/如何查语法错误
1.元素标签必须配对 2.属性必须有引号 3.注意命名
或者直接复制到https://www.runoob.com/xml/xml-validator.html 网页上进行验证
注意:一般专门编辑xml的软件都会有判错功能
C#读取存储XML
XML文件存放位置
1.只读不写的XML文件可以放在Resources或者StreamingAssets 文件夹下
2.动态存储的XML文件放在Application.persistentDataPath 路径下
C#读取XML文件
C#读取XML的方法有几种
1.XmlDocument把数据加载到内存中,方便读取 2.XmlTextReader以流形式加载,内存占用更少,但是是单向只读,使用不是特别方便,除非有特殊需求,否则不会使用 3.Linq以后专门讲Ling的时候讲 使用XmlDocument类读取是较方便最容易理解和操作的方法 读取xml文件信息
XmlDocument xml new XmlDocument();通过XmlDocument读取xml文件 有两个API 1.直接根据xm1字符串内容 来加载xml文件 存放在Resorces文件夹下的xml文件加载处理
TextAsset asset Resources.LoadTextAsset(TestXml);
print(asset.text);
//通过这个方法 就能够翻译字符串为xml对象
xml.LoadXml(asset.trxt));2.是通过xml文件的路径去进行加载
xml. Load(Application.streamingAssetsPath /TestXml.xml);读取元素和属性信息 节点信息类 XmlNode 单个节点信息类 节点列表信息 XmlNodeList 多个节点信息类
获取xml中的根节点
xmlNode root xml.SelectSingleNode(Root);再通过根节点获取下面的子节点
XmlNode nodeName root.SelectSingleNode(name);获取节点包裹的元素信息
print(nodeName.InnerText);获取属性
//两种方式
XmlNode nodeItem root.SelectSingleNode(Item);
print(nodeItem.Attributes[id].Value);
print(nodeItem.Attributes.GetNameItem(id).Value);获取一个节点下的同名节点
XmlNodeList friendList root.SelectNodes(Friend);
//迭代器遍历
foreach(XmlNode item in friendList)
{}
//for循环遍历
for(int i 0;i friendList.Count;i)
{print(friendList[i].SelectSingleNode(name).InnerText);
}总结 1.读取XML文件 XmlDocument xml new XmlDocument(); 读取文本方式1-xml.LoadXml(传入xml文本字符串) 读取文本方式2-xml.Load(传入路径)
2.读取元素和属性 获取单个节点:XmlNode nodexml.SelectSingleNode(节点名) 获取多个节点:XmlNodeList nodeList xml.SelectNodes(节点名)
获取节点元素内容:node.InnerText 获取节点元素属性: 1.item.Attributes[“属性名”].Value 2.item.Attributes.GetNamedItem(“属性名”).Value
通过迭代器遍历或者循环遍历XmlNodeList对象 可以获取到各单个元素节点
C#存储XML文件
决定存储在哪个文件夹下 注意:存储xml文件 在Unity中一定是使用各平台都可读可写可找到的路径 1,Resources 可读 不可写 打包后找不到 × 2.Application.streamingAssetsPath 可读 PC端可写 找得到 × 3.Application.dataPath 打包后找不到 × 4.Application.persistentDataPath 可读可写找得到 √
string path Application.persistentDataPath /PlayerInfo2.xml;
print(Application.persistentDataPath);存储xml文件 关键类 XmlDocument 用于创建节点 存储文件 关键类 XmlDeclaration 用于添加版本信息 关键类 XmlElement 节点类
存储有5步 1.创建文本对象
XmlDocument xml new XmlDocument();2.添加固定版本信息
XmlDeclaration xmlDec xml.CreateXmlDeclaration(1.0,UTF-8,);
xml.AppendChild(xmlDec);3.添加根节点
XmlElement root xml.CreateElement(Root);
xml.AppendChild(root);4.为根节点添加子节点
XmlElement name xml.CreateElement(name);
name.InnerText chx;
root.AppendChild(name);
XmlElement itemList xml.CreateElement(itemList);
itemList.SetAttribute(id,i.ToString());//添加属性
root.AppendChild(itemList);5.保存
xml.Save(path);修改xml文件 1.先判断是否存在文件
if(File.Exists(path))
{
}2.加载后 直接添加节点 移除节点即可
XmlDocument newXml new XmlDocument();
newXml.Load(path);
XmlNode node newXml.SelectSingleNode(Root).SelectSingleNode(atk);
//或者
XmlNode node newXml.SelectSingleNode(Root/atk);
//得到自己的父节点
XmlNode root2 newXml.SelectSingleNode(Root);
//移除子节点方法
root2. RemoveChild(node);
//添加节点
XmlElement speed newXml.CreateElement(moveSpeed);
speed.InnerText 20;
root2.AppendChild(speed);
//保存
newXml.Save(path);实践小项目
必备知识点
XML序列化不支持字典
什么是序列化和反序列化 序列化:把对象转化为可传输的字节序列过程称为序列化 反序列化:把字节序列还原为对象的过程称为反序列化
说人话: 序列化就是把想要存储的内容转换为字节序列用于存储或传递 反序列化就是把存储或收到的字节序列信息解析读取出来使用 xml序列化
public class Lesson1Test
{public int testPublic 10;private int testPrivate 11;protected int testProtected 12;internal int testInternal 13;public string testPUblicStr 123;public int testPro { get; set; }public Lesson1Test2 testClass new Lesson1Test2();
}
public class Lesson1Test2
{public int test1 1;public float test2 1.1f;public bool test3 true;
}1.第一步准备一个数据结构类
Lesson1Test lt new Lesson1Test();2.进行序列化 关键知识点 XmlSerializer 用于序列化对象为xml的关键类 Streamwriter 用于存储文件 using 用于方便流对象释放和销毁 第一步:确定存储路径
string path Application.persistentDataPath /Lesson1Test.xml;第二步:结合 using知识点 和 Streamwriter这个流对象 来写入文件 括号内的代码:写入一个文件流 如果有该文件 直接打开并修改 如果没有该文件 直接新建一个文件 using 的新用法 括号当中包裹的声明的对象 会在 大括号语句块结束后 自动释放掉。当语句块结束会自动帮助我们调用对象的Dispose方法让其进行销毁。using一般都是配合内存占用比较大或者有读写操作时进行使用的。
using(StreamWriter stream new StreamWriter(path))
{//第三步:进行xml文件序列化XmlSerializer s new XmlSerializer(typeof(Lesson1Test));//这句代码的含义 就是通过序列化对象 对我们类对象进行翻译 将其翻译成 我们的xml文件 写入到对应的文件中//第一个参数:文件流对象//第二个参数:想要备翻译 的对象//注意:翻译机器的类型 一定要和传入的对象是一致的 不然会报错s.Serialize(stream, lt);
}存储效果 自定义节点名或设置属性 可以通过特性设置节点或者设置属性并且修改名字
[XmlAttribute(Test1)]
public int test1 1;
[XmlElement(testPublic123123)]
public int testPublic 10;XML反序列化
判断文件是否存在
string path Application.persistentDataPath /Lesson1Test.xml;
if(File.Exists(path))
{
}反序列化 关键知识 1.using 和 StreamReader 2.XmlSerializer的Deserialize反序列化方法
using(StreamReader reader new StreamReader(path))
{XmlSerializer s new XmlSerializer(typeof(Lesson1Test));Lesson1Test lt s.Deserialize(reader) as Lesson1Test;
}List对象如果有默认值反序列化时不会清空会往后面添加。
IXmlSerializable接口
IXmlSerializable是什么 c#的XmlSerializer 提供了可拓展内容 可以让一些不能被序列化和反序列化的特殊类能被处理 让特殊类继承 IXmlSerializable 接口 实现其中的方法即可 自定义类实践
//继承接口
public class TestLesson3 : IXmlSerializable
{public int test1;public string test2;//返回结构public XmlSchema GetSchema(){return null;} //反序列化自动调用public void ReadXml(XmlReader reader){//在里面可以自定义反序列化 的规则//1.读属性this.test1 int.Parse(reader[test1]);this.test2 reader[test2];//2.读节点reader.Read();//这时是读到的test1节点reader.Read();//这时是读到的test1节点包裹的内容this.test1 int.Parse(reader.Value);//3.读包裹元素节点XmlSerializer s new XmlSerializer(typeof(int));//跳过根节点reader.Read();reader.ReadStartElement(test1);test1 (int)s.Deserialize(reader);reader.ReadEndElement();//方式二while(reader.Read()){if( reader.NodeType XmlNodeType.Element ){switch (reader.Name){case test1:reader.Read();this.test1 int.Parse(reader.Value);break;case test2:reader.Read();this.test2 reader.Value;break;}}}}//序列化时自动调用public void WriteXml(XmlWriter writer){//在里面可以自定义序列化 的规则//如果要自定义 序列化的规则 一定会用到 Xmlwriter中的一些方法 来进行序列化//1.写属性writer.WriteAttributeString(test1, this.test1.ToString());writer.WriteAttributeString(test2, this.test2);//2.写节点writer.WriteElementString(test1, this.test1.ToString());writer.WriteElementString(test2, this.test2);//3.写包裹节点XmlSerializer s new XmlSerializer(typeof(int));writer.WriteStartElement(test1);s.Serialize(writer, test1);writer.WriteEndElement();}
}
//序列化
TestLesson3 t new TestLesson3();
string path Application.persistentDataPath /TestLesson3.xml;
using(StreamWriter writer new StreamWriter(path))
{XmlSerializer s new XmlSerializer(typeof(TestLesson3));s.Serialize(writer,t);
}
//反序列化
using (StreamReader reader new StreamReader(path))
{//序列化“翻译机器”XmlSerializer s new XmlSerializer(typeof(TestLesson3));TestLesson3 t2 s.Deserialize(reader) as TestLesson3;
}让Dictionary支持序列化反序列化
思考如何让Dictionary支持xml序列和反序列化 1.我们没办法修改C#自带的类 2.那我们可以重写一个类 继承Dictionary 然后让这个类继承序列化拓展接口IXmlSerializable 3.实现里面的序列化和反序列化方法即可 SerizlizerDictionary.cs
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using UnityEngine;public class SerizlizerDictionaryTKey, TValue : DictionaryTKey, 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 (KeyValuePairTKey, TValue kv in this){//键值对 的序列化keySer.Serialize(writer, kv.Key);valueSer.Serialize(writer, kv.Value);}}
}
Test.cs
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using UnityEngine;public class TestLesson4
{public int test1;public SerizlizerDictionaryint, string dic;
}public class Lesson4 : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){#region 知识点二 让Dictionary支持序列化和反序列化TestLesson4 tl4 new TestLesson4();//tl4.dic new SerizlizerDictionaryint, string();//tl4.dic.Add(1, 123);//tl4.dic.Add(2, 234);//tl4.dic.Add(3, 345);string path Application.persistentDataPath /TestLesson4.xml;//using(StreamWriter writer new StreamWriter(path))//{// XmlSerializer s new XmlSerializer(typeof(TestLesson4));// s.Serialize(writer, tl4);//}using (StreamReader reader new StreamReader(path)){XmlSerializer s new XmlSerializer(typeof(TestLesson4));tl4 s.Deserialize(reader) as TestLesson4;}}// Update is called once per framevoid Update(){}
}