Xml数据持久化

Unity XML 数据持久化

1. 最基础的 XML 序列化示例

假设我们要保存角色数据:

public class RoleInfo
{
    public int hp;
    public int speed;
}

使用 XmlSerializer 序列化:

//保存到xml文件中 data是RoleInfo的对象
public void SavaData(object data,string fileName)
{
    //1.得到存储路径
    string path = Application.persistentDataPath + "/" + fileName + ".xml";
    Debug.Log(path);
    //2.存储文件
    using(StreamWriter writer = new StreamWriter(path))
    {
        XmlSerializer sr = new XmlSerializer(data.GetType());
        //3.序列化
        sr.Serialize(writer, data);
    }
}

反序列化:

//方法二:反序列化到对象中
public T LoadData<T>(string fileName)
{
    string path = Application.persistentDataPath + "/" + fileName + ".xml";
    if (!File.Exists(path))
    {
        path = Application.streamingAssetsPath + "/" + fileName + ".xml";
        if (!File.Exists(path))
        {
            //如果根本不存在路径 那么直接new一个对象给外面 是默认值
            return Activator.CreateInstance<T>();
        }
    }
    using (StreamReader reader = new StreamReader(path))
    {
        XmlSerializer sr = new XmlSerializer(typeof(T));
        return (T)sr.Deserialize(reader);
    }
}

2. [XmlAttribute][XmlElement] 的区别

[XmlAttribute] → 将文本写入为标签的属性

[XmlAttribute] 
public int hp;
[XmlAttribute] 
public int speed;
<role hp="10" speed="5" />

[XmlElement] → 文本InnerText形式(默认的形式)

[XmlElement] 
public int hp;
[XmlElement] 
public int speed;
<role>
    <hp>10</hp>
    <speed>5</speed>
</role>

3. 列表 List 的序列化

假设有角色列表:

public class RoleData
{
    public List<RoleInfo> roleList = new List<RoleInfo>();
}
public class RoleInfo
{
    [XmlAttribute]
    public int hp;
    [XmlAttribute] 
    public int speed;
}

序列化后的XML或自己配置的XML:

<RoleData>
    <roleList>
        <roleInfo hp="4" speed="6"/>
        <roleInfo hp="3" speed="7"/>
    </roleList>
</RoleData>

4. 通用的 XML 管理器:XmlDataMgr(不支持序列化、反序列字典数据)

using System;
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() { }

    // 保存
    public void SavaData(object data, string fileName)
    {
        string path = Application.persistentDataPath + "/" + fileName + ".xml";
        Debug.Log(path);

        using (StreamWriter writer = new StreamWriter(path))
        {
            XmlSerializer sr = new XmlSerializer(data.GetType());
            sr.Serialize(writer, data);
        }
    }

    // 加载(使用 Type)
    public object LoadData(Type type, string fileName)
    {
        string path = Application.persistentDataPath + "/" + fileName + ".xml";

        if (!File.Exists(path))
        {
            path = Application.streamingAssetsPath + "/" + fileName + ".xml";
            if (!File.Exists(path))
            {
                return Activator.CreateInstance(type);
            }
        }

        using (StreamReader reader = new StreamReader(path))
        {
            XmlSerializer sr = new XmlSerializer(type);
            return sr.Deserialize(reader);
        }
    }

    // 加载(泛型)
    public T LoadData<T>(string fileName)
    {
        string path = Application.persistentDataPath + "/" + fileName + ".xml";

        if (!File.Exists(path))
        {
            path = Application.streamingAssetsPath + "/" + fileName + ".xml";
            if (!File.Exists(path))
            {
                return Activator.CreateInstance<T>();
            }
        }

        using (StreamReader reader = new StreamReader(path))
        {
            XmlSerializer sr = new XmlSerializer(typeof(T));
            return (T)sr.Deserialize(reader);
        }
    }
}
  • 自动选择 persistentDataPath 或 streamingAssetsPath
  • 文件不存在时返回默认对象(由程序员自己设计的数据默认值决定)

5. 自定义字典 Dictionary<TKey,TValue> 的序列化(重点)

XmlSerializer 默认 无法直接处理 Dictionary,所以我们通过 IXmlSerializable 自定义规则。
自定义字典的规则无需手动调用,XmlSerializer 会自动使用规则,只需要在定义数据类时使用SerializerDictionary而不是Dictionary
保存、加载正常使用XmlDataMgr即可
完整代码:

using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

public class SerializerDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
    public XmlSchema GetSchema() => null;

    // 反序列化
    public void ReadXml(XmlReader reader)
    {
        XmlSerializer keySer = new XmlSerializer(typeof(TKey));
        XmlSerializer valSer = new XmlSerializer(typeof(TValue));

        reader.Read(); // 跳过根节点

        while (reader.NodeType != XmlNodeType.EndElement)
        {
            TKey key = (TKey)keySer.Deserialize(reader);
            TValue val = (TValue)valSer.Deserialize(reader);
            this.Add(key, val);
        }

        reader.Read(); // 跳过结束节点
    }

    // 序列化
    public void WriteXml(XmlWriter writer)
    {
        XmlSerializer keySer = new XmlSerializer(typeof(TKey));
        XmlSerializer valSer = new XmlSerializer(typeof(TValue));

        foreach (var kv in this)
        {
            keySer.Serialize(writer, kv.Key);
            valSer.Serialize(writer, kv.Value);
        }
    }
}

效果(示例):

<dict>
    <int>1</int>
    <string>hello</string>
    <int>2</int>
    <string>world</string>
</dict>

6. 实践示例:角色数据 XML 文件结构

using System.Collections.Generic;
using System.Xml.Serialization;
public class RoleData
{
    public List<RoleInfo> roleList = new List<RoleInfo>();
}
public class RoleInfo
{
    [XmlAttribute] 
    public int hp;
    [XmlAttribute] 
    public int speed;
    [XmlAttribute] 
    public int volume;
    [XmlAttribute] 
    public string resName;
    [XmlAttribute] 
    public float scale;
}

配置文件 XML 示例:

<?xml version="1.0" encoding="utf-8"?>
<RoleData>
    <roleList>
        <roleInfo hp="4"  speed="6" volume="5" resName="Airplane/Airplane1" scale="15"/>
        <roleInfo hp="3"  speed="7" volume="4" resName="Airplane/Airplane2" scale="15"/>
        <roleInfo hp="2"  speed="8" volume="3" resName="Airplane/Airplane3" scale="15"/>
        <roleInfo hp="10" speed="3" volume="10" resName="Airplane/Airplane4" scale="6"/>
        <roleInfo hp="6"  speed="5" volume="7" resName="Airplane/Airplane5" scale="15"/>
    </roleList>
</RoleData>

获取角色数据相关

//单例DataManager中
private RoleData roleData;
public RoleData RoleData => roleData;
//DataManager私有构造函数中初始化角色数据相关
private DataManager()
{
  roleData = XmlDataMgr.Load<RoleData>(fileName);
}
posted @ 2025-12-03 22:45  高山仰止666  阅读(0)  评论(0)    收藏  举报