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

一、相关介绍

1、XML介绍

XML,全称可拓展标记语言(EX tensible M arkup 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、常用功能实现

csharp 复制代码
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、字典自定义序列化与反序列化实现

csharp 复制代码
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存储与读取功能封装

csharp 复制代码
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);
        }
    }
    
}
相关推荐
一个笔记本2 小时前
godot log | 修改main scene
游戏引擎·godot
nnsix4 小时前
Unity PicoVR开发 实时预览Unity场景 在Pico设备中(串流)
unity·游戏引擎
一只一只10 小时前
Unity之UGUI Button按钮组件详细使用教程
unity·游戏引擎·ugui·button·ugui button
神米米12 小时前
Maya快速安装UE4 布料权重绘制插件PhysX导出apx
游戏引擎·ue4·maya
WarPigs13 小时前
Unity阴影
unity·游戏引擎
一只一只14 小时前
Unity之Invoke
unity·游戏引擎·invoke
阿凉070214 小时前
新版本JLink安装目录中缺失JLinkDevices.xml添加方法
xml·嵌入式硬件
SmalBox14 小时前
【节点】[NormalStrength节点]原理解析与实际应用
unity3d·游戏开发·图形学
技术小甜甜15 小时前
【Godot】【入门】信号系统从 0 到 1(UI/玩法彻底解耦的通用写法)
ui·游戏引擎·godot
Knight_AL16 小时前
从 QueryWrapper 到 XML:一次「报表 SQL」的重构实践
xml·sql·重构