Unity_数据持久化_XML序列化与反序列化

发布于:2025-08-07 ⋅ 阅读:(15) ⋅ 点赞:(0)

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序列化总结

序列化流程:

  1. 有一个想要保存的类对象
  2. 使用XmlSerializer序列化该对象
  3. 通过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;
}

网站公告

今日签到

点亮在社区的每一天
去签到