Unity XML3——XML序列化

一、XML 序列化

​ 序列化:把对象转化为可传输的字节序列过程称为序列化,就是把想要存储的内容转换为字节序列用于存储或传递

​ 反序列化:把字节序列还原为对象的过程称为反序列化,就是把存储或收到的字节序列信息解析读取出来使用

(一)XML 序列化

1.准备数据结构

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    int[]        arrayInt  = new int[3] { 5, 6, 7 };public    List<int> listInt = new List<int>() { 1, 2, 3, 4 };public    List<Lesson1Test2> listItem = new List<Lesson1Test2>() { new Lesson1Test2(), new Lesson1Test2() };// 不支持字典// public Dictionary<int, string> testDic = new Dictionary<int, string>() { { 1, "123" } };
}public class Lesson1Test2
{public int test1 = 1;public float test2 = 1.1f;public bool test3 = true;
}Lesson1Test lt = new Lesson1Test();

2.进行序列化

XmlSerializer:用于序列化对象为 xml 的关键类

StreamWriter:用于存储文件

using:用于方便流对象释放和销毁

using System.Xml.Serialization;// 第一步:确定存储路径
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);
}

3.运行测试

运行后可以看到如下的文件内容(在 path 文件夹中查看)

可以发现,只能保存 public 类型的数据

<?xml version="1.0" encoding="utf-8"?>
<Lesson1Test xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><testPublic>10</testPublic><testPUblicStr>123</testPUblicStr><testClass><test1>1</test1><test2>1.1</test2><test3>true</test3></testClass><arrayInt><int>5</int><int>6</int><int>7</int></arrayInt><listInt><int>1</int><int>2</int><int>3</int><int>4</int></listInt><listItem><Lesson1Test2><test1>1</test1><test2>1.1</test2><test3>true</test3></Lesson1Test2><Lesson1Test2><test1>1</test1><test2>1.1</test2><test3>true</test3></Lesson1Test2></listItem><testPro>0</testPro>
</Lesson1Test>

4.自定义节点名或设置属性

public class Lesson1Test
{[XmlElement("testPublic123123")]  // 将该变量对应的结点名字改为 "testPublic123123"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    int[]        arrayInt  = new int[3] { 5, 6, 7 };[XmlArray("IntList")]    // 改变数组对应的结点名字[XmlArrayItem("Int32")]  // 改变数组成员对应的结点名字public List<int> listInt = new List<int>() { 1, 2, 3, 4 };public List<Lesson1Test2> listItem = new List<Lesson1Test2>() { new Lesson1Test2(), new Lesson1Test2() };// 不支持字典// public Dictionary<int, string> testDic = new Dictionary<int, string>() { { 1, "123" } };
}public class Lesson1Test2
{[XmlAttribute("Test1")]    // 将该变量存储为XML属性,并改名为 "Test1"public int test1 = 1;[XmlAttribute]             // 将该变量存储为XML属性public float test2 = 1.1f;[XmlAttribute]          public bool test3 = true;
}
<?xml version="1.0" encoding="utf-8"?>
<Lesson1Test xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><testPublic>10</testPublic><testPUblicStr>123</testPUblicStr><testClass Test1="1" test2="1.1" test3="true" /><arrayInt><int>5</int><int>6</int><int>7</int></arrayInt><IntList><Int32>1</Int32><Int32>2</Int32><Int32>3</Int32><Int32>4</Int32></IntList><listItem><Lesson1Test2 Test1="1" test2="1.1" test3="true" /><Lesson1Test2 Test1="1" test2="1.1" test3="true" /></listItem><testPro>0</testPro>
</Lesson1Test>

​5. 总结:

  • 序列化流程
    1. 有一个想要保存的类对象
    2. 使用 XmlSerializer 序列化该对象
    3. 通过 StreamWriter 配合 using 将数据存储 写入文件
  • 注意:
    1. 只能序列化公共成员
    2. 不支持字典序列化
    3. 可以通过特性修改节点信息或者设置属性信息
    4. Stream 相关要配合 using 使用

二、XML 反序列化

(一)判断文件是否存在

using System.IO;string path = Application.persistentDataPath + "/Lesson1Test.xml";
if(File.Exists(path)) { ... }

(二)反序列化

​ 关键知识:

  1. using 和 StreamReader
  2. XmlSerializer 的 Deserialize 反序列化方法
using System.Xml.Serialization;// 读取文件
using (StreamReader reader = new StreamReader(path))
{// 产生了一个 序列化反序列化的翻译机器XmlSerializer s = new XmlSerializer(typeof(Lesson1Test));Lesson1Test lt = s.Deserialize(reader) as Lesson1Test;
}

​ 运行后调试,可以发现 List 类型的内容被重复添加,原因是变量 lt 初始化后, List 中有默认值,而反序列化时,Deserialize 方法会往 List 中用 Add 方法添加值,而不是覆盖原有的值。

​ 总结:

  1. 判断文件是否存在 File.Exists()

  2. 文件流获取 StreamReader reader = new StreamReader(path)

  3. 根据文件流 XmlSerializer 通过 Deserialize 反序列化出对象

​ 注意:List 对象如果有默认值,反序列化时不会清空,会往后面添加

三、IXmlSerializable 接口

​ C# 的 XmlSerializer 提供了可拓展内容,可以让一些不能被序列化和反序列化的特殊类能被处理
​ 让特殊类继承 IXmlSerializable 接口,实现其中的方法即可

(一)回顾序列化与反序列化

using System.IO;
using System.Xml;
using System.Xml.Serialization;public class TestLesson3 : IXmlSerializable
{public int test1;public string test2;
}TestLesson3 t = new TestLesson3();
t.test2 = "123";
string path = Application.persistentDataPath + "/TestLesson3.xml";
// 序列化
using (StreamWriter writer = new StreamWriter(path))
{// 序列化"翻译机器"XmlSerializer s = new XmlSerializer(typeof(TestLesson3));// 在序列化时  如果对象中的引用成员 为空 那么xml里面是看不到该字段的s.Serialize(writer, t);
}
// 反序列化
using (StreamReader reader = new StreamReader(path))
{// 序列化"翻译机器"XmlSerializer s = new XmlSerializer(typeof(TestLesson3));TestLesson3 t2 = s.Deserialize(reader) as TestLesson3;
}
<?xml version="1.0" encoding="utf-8"?>
<TestLesson3 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><test1>0</test1><test2>123</test2>
</TestLesson3>

(二)继承 IXmlSerializable 接口

1.继承接口并实现接口函数

public class TestLesson3 : IXmlSerializable
{public int test1;public string test2;// 返回结构,返回 null 即可,不用过多了解public XmlSchema GetSchema(){return null;}// 反序列化时 会自动调用的方法public void ReadXml(XmlReader reader) { }// 序列化时 会自动调用的方法public void WriteXml(XmlWriter writer) { }
}

2.WriteXml

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");  // 写 <test1>s.Serialize(writer, test1);         // 用序列化翻译机器写 test1 的内容writer.WriteEndElement();           // 写 </test1>XmlSerializer s2 = new XmlSerializer(typeof(string));writer.WriteStartElement("test2");  // 写 <test2>s.Serialize(writer, test2);         // 用序列化翻译机器写 test2 的内容writer.WriteEndElement();           // 写 </test2>
}

3.ReadXml

public void ReadXml(XmlReader reader)
{// 在里面可以自定义反序列化 的规则// 1.读属性this.test1 = int.Parse(reader["test1"]);this.test2 = reader["test2"];// 2.读节点// 方式一reader.Read();                         // 这时是读到的test1节点          <test1>reader.Read();                         // 这时是读到的test1节点包裹的内容  0this.test1 = int.Parse(reader.Value);  // 得到当前内容的值=reader.Read();                         // 这时读到的是尾部包裹节点        </test1>reader.Read();                         // 这时是读到的test2节点          <test2>reader.Read();                         // 这时是读到的test2节点包裹的内容  123this.test2 = reader.Value;// 方式二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;}}}// 3.读包裹元素节点XmlSerializer s = new XmlSerializer(typeof(int));XmlSerializer s2 = new XmlSerializer(typeof(string));reader.Read();  // 跳过根节点reader.ReadStartElement("test1");     // 读 <test1>test1 = (int)s.Deserialize(reader);   // 用反序列化翻译机器读 test1 的内容reader.ReadEndElement();              // 读 </test1>reader.ReadStartElement("test2");            // 读 <test2>test2 = s2.Deserialize(reader).ToString();   // 用反序列化翻译机器读 test2 的内容reader.ReadEndElement();                     // 读 </test2>
}

四、Dictionary 支持序列化与反序列化

  1. 我们没办法修改 C# 自带的类

  2. 那我们可以重写一个类继承 Dictionary,然后让这个类继承序列化拓展接口 IXmlSerializable

  3. 实现里面的序列化和反序列化方法即可

public class SerizlizedDictionary<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);}}// 自定义 字典的 序列化 规则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);}}
}

(一)序列化测试

public class TestLesson4
{public int test1;public SerizlizerDictionary<int, string> dic;
}public class Lesson4 : MonoBehaviour
{// Start is called before the first frame updatevoid Start() {TestLesson4 tl4 = new TestLesson4();tl4.dic = new SerizlizerDictionary<int, 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);}}
}
<?xml version="1.0" encoding="utf-8"?>
<TestLesson4 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><test1>0</test1><dic><int>1</int><string>123</string><int>2</int><string>234</string><int>3</int><string>345</string></dic>
</TestLesson4>

(二)反序列化测试

void Start() {TestLesson4 tl4 = new TestLesson4();using (StreamReader reader = new StreamReader(path)) {XmlSerializer s = new XmlSerializer(typeof(TestLesson4)); tl4 = s.Deserialize(reader) as TestLesson4;}
}

五、自定义 XML 数据管理类

using System;
using System.IO;
using System.Xml.Serialization;
using UnityEngine;public class XmlDataMgr
{// 单例模式public static XmlDataMgr Instance { get; } = new XmlDataMgr();// 防止外部实例化该管理类private XmlDataMgr() { }/// <summary>/// 保存数据到xml文件中/// </summary>/// <param name="data">数据对象</param>/// <param name="fileName">文件名</param>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);}}/// <summary>/// 从xml文件中读取内容 /// </summary>/// <param name="type">对象类型</param>/// <param name="fileName">文件名</param>/// <returns></returns>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);}}
}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);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/11022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

尚医通06:数据字典+EasyExcel+mongodb

内容介绍 1、数据字典列表前端 2、EasyExcel介绍、实例 3、数据字典导出接口、前端 4、数据字典导入接口、前端 5、数据字典添加redis缓存 6、MongoDB简介 7、MongoDB安装 8、MongoDB基本概念 数据字典列表前端 1、测试问题 &#xff08;1&#xff09;报错日志 &am…

SpringBoot复习:(4)打成的jar包是如何启动的?

jar包通过MANIFEST的Main-Class指定了主类JarLauncher, JarLauncher的main方法代码如下&#xff1a; 其中调用的launch的代码如下&#xff1a; 首先&#xff0c;创建了一个自定义的ClassLoader,代码如下&#xff1a; 其中调用的重载的createClassLoader代码如下&#xff1…

STM32MP157驱动开发——按键驱动(中断)

文章目录 编写使用中断的按键驱动程序编程思路设备树相关驱动代码相关 代码修改设备树文件gpio_key_drv.cMakefile编译测试 编写使用中断的按键驱动程序 对于使用中断的按键驱动&#xff0c;内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以&#xff0c;需要做的…

cpolar内网穿透工具

文章目录 cpolar内网穿透工具 cpolar内网穿透工具 科学技术的发展日新月异&#xff0c;电子设备在人们的生活中已成为不可或缺的工具&#xff0c;甚至在很多情况下&#xff0c;各类型的电子设备已经成为工作的核心&#xff0c;虽然移动设备越来越小巧&#xff0c;功能也越来越…

基于netlify生成custom SSL certificate

&#xff08;1&#xff09;腾讯云申请 &#xff08;2&#xff09;域名控制台解析 &#xff08;3&#xff09;Nginx下载&#xff08;crt: CA certificate Chain)

SpringBoot 8种异步实现方式

前言&#xff1a;异步执行对于开发者来说并不陌生&#xff0c;在实际的开发过程中&#xff0c;很多场景多会使用到异步&#xff0c;相比同步执行&#xff0c;异步可以大大缩短请求链路耗时时间&#xff0c;比如&#xff1a;「发送短信、邮件、异步更新等」&#xff0c;这些都是…

如何解决大数据下滚动页面卡顿问题

原文合集地址如下&#xff0c;有需要的朋友可以关注 本文地址 合集地址 前言 之前遇到不分页直接获取到全部数据&#xff0c;前端滚动查看数据&#xff0c;页面就听卡顿的&#xff0c;当然这和电脑浏览器性能啥的还是有点关系。但根源还是一次性渲染数据过多导致的&#xf…

【C++从0到王者】第十三站:vector源码分析及手把手教你如何写一个简单的vector

文章目录 一、vector的源码分析1.分析思路2.构造函数和插入接口 二、手把手教你写一个简单的vector1.基本结构2.迭代器与私有成员变量的定义3.构造函数4.size和capacity5.迭代器函数接口6.析构函数7.reserve接口8.尾插9.operator[]运算符重载10.简单的测试前面的接口11.insert以…

【043】解密C++ STL:深入理解并使用 list 容器

解密C STL&#xff1a;深入理解并使用list容器 引言一、list 容器概述二、list容器常用的API2.1、构造函数2.2、数据元素插入和删除操作2.3、大小操作2.4、赋值操作2.5、数据的存取2.6、list容器的反转和排序 三、使用示例总结 引言 &#x1f4a1; 作者简介&#xff1a;一个热爱…

2023年深圳杯数学建模D题基于机理的致伤工具推断

2023年深圳杯数学建模 D题 基于机理的致伤工具推断 原题再现&#xff1a; 致伤工具的推断一直是法医工作中的热点和难点。由于作用位置、作用方式的不同&#xff0c;相同的致伤工具在人体组织上会形成不同的损伤形态&#xff0c;不同的致伤工具也可能形成相同的损伤形态。致伤…

7D透明屏的市场应用广泛,在智能家居中有哪些应用表现?

7D透明屏是一种新型的显示技术&#xff0c;它能够实现透明度高达70%以上的显示效果。这种屏幕可以应用于各种领域&#xff0c;如商业广告、展览展示、智能家居等&#xff0c;具有广阔的市场前景。 7D透明屏的工作原理是利用光学投影技术&#xff0c;将图像通过透明屏幕投射出来…

Talk | 南洋理工大学博士后研究员李祥泰:基于Transformer的视觉分割模型总结、回顾与展望

​ 本期为TechBeat人工智能社区第517期线上Talk&#xff01; 北京时间7月27日(周四)20:00&#xff0c;南洋理工大学博士后研究员—李祥泰的Talk已经准时在TechBeat人工智能社区开播了&#xff01; 他与大家分享的主题是: “基于Transformer的视觉分割模型总结、回顾与展望”&am…

C#多线程

C#多线程 C#多线程是C#学习中必不可少的知识&#xff0c;在实际开发中也能有效的提升用户体验&#xff0c;和程序性能。 文章目录 C#多线程前言一、什么是线程、什么是进程、什么是协程&#xff1f;协程优点缺点 线程优点缺点&#xff1a; 进程优点缺点&#xff1a; 二、C# 中…

使用Spring Boot实现Redis键过期回调功能

使用Spring Boot实现Redis键过期回调功能 当使用Redis作为缓存或数据存储的时候&#xff0c;有时候需要在键过期时执行一些特定的操作&#xff0c;比如清除相关数据或发送通知。在Spring Boot中&#xff0c;可以通过实现RedisMessageListener接口来实现Redis键过期回调功能。下…

基于“RWEQ+”集成技术在土壤风蚀模拟与风蚀模数估算、变化归因分析中的实践应用及SCI论文撰写

查看原文>>>基于“RWEQ”集成技术在土壤风蚀模拟与风蚀模数估算、变化归因分析中的实践应用及SCI论文撰写 土壤风蚀是一个全球性的环境问题。中国是世界上受土壤风蚀危害最严重的国家之一&#xff0c;土壤风蚀是中国干旱、半干旱及部分湿润地区土地荒漠化的首要过程。…

B2B企业如何选择CRM系统?

CRM软件的优势在于简化业务流程&#xff0c;实现企业的降本增效。越来越多的B2B企业通过CRM为业务赋能&#xff0c;B2B企业如何快速找到适合公司业务的CRM系统&#xff1f;总的来说就是根据企业自身业务而量身打造的一套系统。 1.整理业务需求 B2B企业首先要考虑是业务痛点&a…

MySQL绿色安装和配置

1、 从地址http://dev.mysql.com/downloads/mysql/中选择windows的版本下载。 2、 mysql各个版本的简介 &#xff08;1&#xff09; MySQL Community Server 社区版本&#xff0c;开源免费&#xff0c;但不提供官方技术支持。 &#xff08;2&#xff09; MySQL Enterprise Ed…

Spring MVC

一、什么是MVC MVC就是一种思想&#xff0c;而Spring MVC是对MVC思想的具体实现 MVC是Model View Controller的所缩写&#xff0c;是一种软件架构模式&#xff0c;它将软件系统Fenwick墨香&#xff0c;视图和控制器三个基本部分。 Model&#xff1a;是应用程序中用于处理应用…

7.27 Qt

制作简易小闹钟 Timer.pro QT core gui texttospeechgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # dep…

Cisco 路由器配置管理

大多数网络中断的最常见原因是错误的配置更改。对网络设备配置的每一次更改都伴随着造成网络中断、安全问题甚至性能下降的风险。计划外更改使网络容易受到意外中断的影响。 Network Configuration Manager 网络更改和配置管理 &#xff08;NCCM&#xff09;解决方案&#xff…