【Unity开发】数据存储——XML

发布于:2025-07-25 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、相关介绍

1、XML介绍

XML,全称可拓展标记语言(EXtensible Markup Language),是被设计用于传输和存储数据的一种文本特殊格式。

2、优缺点

优点:格式统一,符合标准,容易与其他系统进行远程交互,数据共享比较方便。
缺点:XML文件庞大,文件格式复杂,传输占带宽;服务器端与客户端解析XML花费较多的资源和时间。

3、基本规则

①每个元素都必须有关闭标签
②元素命名规则基本遵照C#中变量名命名规则
③XML标签对大小写敏感
④XML文档必须有根元素
⑤特殊的符号应该用实体引用
在这里插入图片描述

4、XML属性

(1)属性语法

在这里插入图片描述

(2)属性和元素节点的区别(只有写法上的区别)

在这里插入图片描述

5、如何检查语法错误

①元素标签必须配对
②属性必须有引号
③注意命名
④将内容直接复制到该网站进行验证:https://www.runoob.com/xml/xml-validator.html

6、XML存放位置

①只读不写,存放在Resources或者StreamingAssets文件夹下
②动态存储,放在Application.persistentDataPath路径下

二、具体实现

1、常用功能实现

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using UnityEngine;

public class LoadXml : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        #region 读取xml文件信息
        //方法一、读取Resources文件夹下的xml文件加载处理
        TextAsset textAsset = Resources.Load<TextAsset>("TestXml");
        print(textAsset.text);
        XmlDocument xml = new XmlDocument();
        xml.LoadXml(textAsset.text);

        //方法二、读取StreamingAssets文件夹下的xml文件加载处理
        //xml.Load(Application.streamingAssetsPath + "/Testxml.xml");
        #endregion

        #region 读取元素和属性信息
        //1、获取xml中的根节点
        XmlNode root = xml.SelectSingleNode("Root");

        //2、通过根节点获取下面的字节点
        XmlNode nodeName = root.SelectSingleNode("name");

        //3、获取节点包裹的元素信息
        print(nodeName.InnerText);

        //4、获取节点属性信息
        XmlNode nodeItem = root.SelectSingleNode("Item");
        //方式一
        print(nodeItem.Attributes["id"].Value);
        print(nodeItem.Attributes["num"].Value);
        //方式二
        print(nodeItem.Attributes.GetNamedItem("id").Value);
        print(nodeItem.Attributes.GetNamedItem("num").Value);

        //5、获取一个节点下的同名节点的方法
        XmlNodeList friendList = root.SelectNodes("Friend");
        //遍历打印信息
        //方法一、使用迭代器遍历
        foreach (XmlNode item in friendList)
        {
            print(item.SelectSingleNode("name").InnerText);
            print(item.SelectSingleNode("age").InnerText);
        }
        //方法二、使用for循环遍历
        for (int i = 0; i < friendList.Count; i++)
        {
            print(friendList[i].SelectSingleNode("name").InnerText);
            print(friendList[i].SelectSingleNode("age").InnerText);
        }
        #endregion

        #region 存储xml文件信息
        //1、存储路径
        //Resources 可读 不可写 打包后找不到 x
        //Application.streamingAssetsPath 可读 PC端可写 找得到 x
        //Application.dataPath 打包后找不到 x
        //Application.persistentDataPath 可读可写找得到 ✔
        string path = Application.persistentDataPath + "/PlayerInfo2.xml";
        print(path);

        //2、存储xml文件
        //(1)创建文本对象
        XmlDocument xml1 = new XmlDocument();
        //(2)添加固定版本信息
        XmlDeclaration xmlDec = xml1.CreateXmlDeclaration("1.0", "UTF-8", "");
        xml1.AppendChild(xmlDec);
        //(3)添加根节点
        XmlElement root1 = xml1.CreateElement("Root");
        xml1.AppendChild(root1);
        //(4)为根节点添加子节点
        XmlElement name = xml1.CreateElement("name");
        name.InnerText = "某某某";
        root1.AppendChild(name);

        XmlElement listInt = xml1.CreateElement("int");
        for (int i = 0; i < 3; i++)
        {
            XmlElement childNode = xml1.CreateElement("int");
            childNode.InnerText = i.ToString();
            listInt.AppendChild(childNode);
        }
        root1.AppendChild(listInt);
        //(5)添加属性
        XmlElement itemList = xml1.CreateElement("itemList");
        for (int i = 0; i < 3; i++)
        {
            XmlElement childNode = xml1.CreateElement("Item");
            //添加属性
            childNode.SetAttribute("id", i.ToString());
            childNode.SetAttribute("num", (i * 10).ToString());
            itemList.AppendChild(childNode);
        }
        root1.AppendChild(itemList);
        //(6)保存
        xml1.Save(path);
        print("成功保存到文件夹:" + path);
        #endregion

        #region 修改xml文件信息
        //1、先判断是否存在文件
        if (File.Exists(path))
        {
            //2、加载后 直接添加节点 移除节点即可
            XmlDocument xml2 = new XmlDocument();
            xml2.Load(path);

            //移除
            XmlNode node = xml2.SelectSingleNode("Root").SelectSingleNode("name");
            node = xml2.SelectSingleNode("Root/name");
            print(node.InnerText);

            //得到自己的父节点
            XmlNode root2 = xml2.SelectSingleNode("Root");
            root2.RemoveChild(node);

            //添加
            XmlNode speed = xml2.CreateElement("moveSpeed");
            speed.InnerText = "20";
            root.AppendChild(speed);

            //修改后 记得保存更新xml文件
            xml2.Save(path);
        }

        #endregion
    }
}

2、字典自定义序列化与反序列化实现

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

public class SerizlizerDictionary<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);
        }
        reader.Read();
    }

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

3、XML存储与读取功能封装

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

    /// <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);
        }
    }
    
}

网站公告

今日签到

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