Unity数据持久化
三、XML数据持久化
3.4 XML序列化与反序列化
3.4.1 序列化基础概念
序列化定义:
序列化是把对象转化为可传输的字节序列过程称为序列化。
反序列化定义:
反序列化是把字节序列还原为对象的过程称为反序列化。
通俗解释:
- 序列化:把想要存储的内容转换为字节序列用于存储或传递
- 反序列化:把存储或收到的字节序列信息解析读取出来使用
核心理解:
序列化就是将内存中的对象转换为可以存储或传输的格式,反序列化则是将这个格式重新转换回内存中的对象。
3.4.2 XML序列化核心知识点
XML序列化流程:
1. 第一步:准备一个数据结构类
// 定义要序列化的数据结构
public class Lesson1Test
{
public string name = "张三";
public int age = 25;
public float height = 1.75f;
public bool isStudent = true;
// 无参构造函数(序列化需要)
public Lesson1Test() { }
}
// 创建对象实例
Lesson1Test lt = new Lesson1Test();
2. 第二步:进行序列化
// 关键知识点
// XmlSerializer 用于序列化对象为XML的关键类
// StreamWriter 用于存储文件
// using 用于方便流对象释放和销毁
// 第一步:确定存储路径
string path = Application.persistentDataPath + "/Lesson1Test.xml";
print(Application.persistentDataPath);
// 第二步:结合 using知识点 和 StreamWriter这个流对象来写入文件
// 括号内的代码:写入一个文件流 如果有该文件直接打开并修改如果没有该文件直接新建一个文件
// using 的新用法 括号当中包裹的声明的对象 会在大括号语句块结束后自动释放掉
// 当语句块结束 会自动帮助我们调用对象的 Dispose这个方法让其进行销毁
// using一般都是配合 内存占用比较大或者有读写操作时进行使用的
using (StreamWriter stream = new StreamWriter(path))
{
// 第三步:进行xml文件序列化
// 这句代码的含义就是通过序列化对象对我们类对象进行翻译 将其翻译成我们的xml文件写入到对应的文件
// 第一个参数:文件流对象
// 第二个参数:想要被翻译的对象
// 注意:翻译机器的类型一定要和传入的对象是一致的不然会报错
XmlSerializer s = new XmlSerializer(typeof(Lesson1Test));
s.Serialize(stream, lt);
}
3.4.3 实用XML序列化示例
基于实际项目的XML序列化实现:
using UnityEngine;
using System.Xml.Serialization;
using System.IO;
using System.Collections.Generic;
/// <summary>
/// 文本数据类 - 包含各种数据类型
/// </summary>
public class TextData
{
public string text = "gsffs";
public int age;
public List<string> list;
public int[] array = new int[3] { 1, 2, 3 };
// 无参构造函数(序列化需要)
public TextData() { }
}
/// <summary>
/// XML序列化实用示例类
/// 演示完整的序列化和反序列化流程
/// </summary>
public class XmlSerilizef : MonoBehaviour
{
void Start()
{
// 确定存储路径
string path = Application.persistentDataPath + "/TextData.xml";
print("存储路径: " + path);
// 创建测试数据
TextData textData = new TextData();
textData.list = new List<string>() { "1", "2", "3" };
textData.age = 25;
// 序列化对象到XML文件
SerializeToXml(textData, path);
// 从XML文件反序列化对象
TextData textData2 = DeserializeFromXml(path);
// 验证反序列化结果
if (textData2 != null)
{
print("反序列化成功!");
print("文本: " + textData2.text);
print("年龄: " + textData2.age);
// 遍历列表数据
print("列表内容:");
foreach (string s in textData2.list)
{
print(s);
}
// 遍历数组数据
print("数组内容:");
foreach (int i in textData2.array)
{
print(i);
}
}
}
/// <summary>
/// 序列化对象到XML文件
/// </summary>
/// <param name="data">要序列化的对象</param>
/// <param name="path">文件路径</param>
private void SerializeToXml(TextData data, string path)
{
try
{
// 创建XmlSerializer实例
XmlSerializer ser = new XmlSerializer(typeof(TextData));
// 使用using语句确保资源正确释放
using (StreamWriter sw = new StreamWriter(path))
{
ser.Serialize(sw, data);
}
print("序列化成功!");
}
catch (System.Exception e)
{
print("序列化失败: " + e.Message);
}
}
/// <summary>
/// 从XML文件反序列化对象
/// </summary>
/// <param name="path">文件路径</param>
/// <returns>反序列化的对象</returns>
private TextData DeserializeFromXml(string path)
{
try
{
// 创建XmlSerializer实例
XmlSerializer ser = new XmlSerializer(typeof(TextData));
// 使用using语句确保资源正确释放
using (StreamReader sr = new StreamReader(path))
{
TextData data = (TextData)ser.Deserialize(sr);
return data;
}
}
catch (System.Exception e)
{
print("反序列化失败: " + e.Message);
return null;
}
}
}
关键知识点解析:
1. 数据类型支持
public class TextData
{
public string text; // 字符串类型
public int age; // 整数类型
public List<string> list; // 列表类型
public int[] array; // 数组类型
}
2. 序列化流程
// 第一步:创建XmlSerializer实例
XmlSerializer ser = new XmlSerializer(typeof(TextData));
// 第二步:使用StreamWriter写入文件
using (StreamWriter sw = new StreamWriter(path))
{
// 第三步:执行序列化
ser.Serialize(sw, data);
}
3. 反序列化流程
// 第一步:创建XmlSerializer实例
XmlSerializer ser = new XmlSerializer(typeof(TextData));
// 第二步:使用StreamReader读取文件
using (StreamReader sr = new StreamReader(path))
{
// 第三步:执行反序列化
TextData data = (TextData)ser.Deserialize(sr);
}
3.4.4 XML序列化完整示例
完整的XML序列化实现:
using UnityEngine;
using System.Xml.Serialization;
using System.IO;
/// <summary>
/// XML序列化示例类
/// 演示如何使用XmlSerializer进行对象序列化和反序列化
/// </summary>
public class XmlSerializationExample : MonoBehaviour
{
void Start()
{
// 创建测试数据
Lesson1Test testData = new Lesson1Test();
// 序列化对象到XML文件
SerializeToXml(testData);
// 从XML文件反序列化对象
Lesson1Test loadedData = DeserializeFromXml();
// 验证反序列化结果
if(loadedData != null)
{
Debug.Log("姓名: " + loadedData.name);
Debug.Log("年龄: " + loadedData.age);
Debug.Log("身高: " + loadedData.height);
Debug.Log("是否学生: " + loadedData.isStudent);
}
}
/// <summary>
/// 序列化对象到XML文件
/// </summary>
/// <param name="data">要序列化的对象</param>
private void SerializeToXml(Lesson1Test data)
{
// 确定存储路径
string path = Application.persistentDataPath + "/Lesson1Test.xml";
Debug.Log("存储路径: " + path);
try
{
// 使用using语句确保资源正确释放
using (StreamWriter stream = new StreamWriter(path))
{
// 创建XmlSerializer实例
XmlSerializer serializer = new XmlSerializer(typeof(Lesson1Test));
// 执行序列化
serializer.Serialize(stream, data);
Debug.Log("序列化成功,文件已保存到: " + path);
}
}
catch (System.Exception e)
{
Debug.LogError("序列化失败: " + e.Message);
}
}
/// <summary>
/// 从XML文件反序列化对象
/// </summary>
/// <returns>反序列化的对象</returns>
private Lesson1Test DeserializeFromXml()
{
string path = Application.persistentDataPath + "/Lesson1Test.xml";
// 检查文件是否存在
if (!File.Exists(path))
{
Debug.LogWarning("XML文件不存在: " + path);
return null;
}
try
{
// 使用using语句确保资源正确释放
using (StreamReader stream = new StreamReader(path))
{
// 创建XmlSerializer实例
XmlSerializer serializer = new XmlSerializer(typeof(Lesson1Test));
// 执行反序列化
Lesson1Test data = (Lesson1Test)serializer.Deserialize(stream);
Debug.Log("反序列化成功");
return data;
}
}
catch (System.Exception e)
{
Debug.LogError("反序列化失败: " + e.Message);
return null;
}
}
}
/// <summary>
/// 测试数据结构类
/// </summary>
[System.Serializable]
public class Lesson1Test
{
// 基本数据类型
public string name = "张三";
public int age = 25;
public float height = 1.75f;
public bool isStudent = true;
// 数组类型
public int[] scores = { 85, 90, 78, 92, 88 };
// 列表类型
public List<string> hobbies = new List<string> { "读书", "游戏", "运动" };
// 无参构造函数(序列化需要)
public Lesson1Test() { }
// 有参构造函数
public Lesson1Test(string name, int age, float height)
{
this.name = name;
this.age = age;
this.height = height;
}
}
3.4.4 XML序列化总结
序列化流程:
- 有一个想要保存的类对象
- 使用XmlSerializer序列化该对象
- 通过StreamWriter配合using将数据存储写入文件
重要注意事项:
1. 只能序列化公共成员
public class TestClass
{
public string publicField; // 可以序列化
private string privateField; // 不能序列化
public string PublicProperty { get; set; } // 可以序列化
private string PrivateProperty { get; set; } // 不能序列化
}
2. 不支持字典序列化
public class TestClass
{
public List<string> list; // 可以序列化
public Dictionary<string, int> dict; // 不能直接序列化
}
3. 可以通过特性修改节点信息或者设置属性信息
public class TestClass
{
[XmlElement("PlayerName")] // 修改XML节点名称
public string name;
[XmlAttribute("PlayerAge")] // 将字段作为属性存储
public int age;
[XmlIgnore] // 忽略此字段,不进行序列化
public string tempData;
}
4. Stream相关要配合using使用
// 正确的使用方式
using (StreamWriter stream = new StreamWriter(path))
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
serializer.Serialize(stream, data);
}
// 错误的使用方式(可能导致资源泄漏)
StreamWriter stream = new StreamWriter(path);
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
serializer.Serialize(stream, data);
// 忘记调用stream.Close()或stream.Dispose()
5. 必须有无参构造函数
public class TestClass
{
public string name;
public int age;
// 必须有无参构造函数,否则序列化会失败
public TestClass() { }
// 可以有其他构造函数
public TestClass(string name, int age)
{
this.name = name;
this.age = age;
}
}
6. 类型一致性要求
// 序列化和反序列化时,类型必须完全一致
XmlSerializer ser = new XmlSerializer(typeof(TextData)); // 类型必须匹配
TextData data = (TextData)ser.Deserialize(stream); // 强制转换类型
1. 只能序列化公共成员
public class TestClass
{
public string publicField; // 可以序列化
private string privateField; // 不能序列化
public string PublicProperty { get; set; } // 可以序列化
private string PrivateProperty { get; set; } // 不能序列化
}
2. 不支持字典序列化
public class TestClass
{
public List<string> list; // 可以序列化
public Dictionary<string, int> dict; // 不能直接序列化
}
3. 可以通过特性修改节点信息或者设置属性信息
public class TestClass
{
[XmlElement("PlayerName")] // 修改XML节点名称
public string name;
[XmlAttribute("PlayerAge")] // 将字段作为属性存储
public int age;
[XmlIgnore] // 忽略此字段,不进行序列化
public string tempData;
}
4. Stream相关要配合using使用
// 正确的使用方式
using (StreamWriter stream = new StreamWriter(path))
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
serializer.Serialize(stream, data);
}
// 错误的使用方式(可能导致资源泄漏)
StreamWriter stream = new StreamWriter(path);
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
serializer.Serialize(stream, data);
// 忘记调用stream.Close()或stream.Dispose()
3.4.5 XML序列化高级特性
1. 自定义XML节点名称
public class PlayerData
{
[XmlElement("PlayerName")]
public string name;
[XmlElement("PlayerLevel")]
public int level;
[XmlElement("PlayerClass")]
public string playerClass;
}
2. 使用XML属性存储数据
public class ItemData
{
[XmlAttribute("ItemID")]
public int id;
[XmlAttribute("ItemName")]
public string name;
[XmlAttribute("ItemCount")]
public int count;
}
3. 忽略特定字段
public class GameData
{
public string playerName;
public int score;
[XmlIgnore]
public string temporaryData; // 不会被序列化
[XmlIgnore]
public System.DateTime lastSaveTime; // 不会被序列化
}
4. 处理复杂数据结构
public class GameSaveData
{
public PlayerInfo playerInfo;
public List<ItemInfo> inventory;
public GameSettings settings;
public GameSaveData()
{
playerInfo = new PlayerInfo();
inventory = new List<ItemInfo>();
settings = new GameSettings();
}
}
public class PlayerInfo
{
public string name;
public int level;
public float experience;
}
public class ItemInfo
{
[XmlAttribute("ID")]
public int id;
[XmlAttribute("Count")]
public int count;
}
public class GameSettings
{
public float musicVolume;
public float soundVolume;
public bool fullscreen;
}