zoukankan      html  css  js  c++  java
  • XML数据持久化学习笔记

    一.XML基础语法

      1.XML结构:XML是一种树结构的文本

      2.XML注释:格式:<!--在其中书写注释-->,在注释中可以单行注释也可以多行注释

      3.固定内容:<?xml version="1.0" encoding="UTF-8"?>版本和编码信息

      4.基本语法:<root>...</root>,一个节点的内容使用尖括号包裹节点名称开始,尖括号包裹斜杠和节点名称结束,子节点的内容被包裹在这两个尖括号中间。通过在最下层的子节点的首尾尖括号之间包裹数据的形式保存数据。这种节点的树形结构和对象这种引用类型中包含值类型(没有子节点)和其他引用类型(有子节点)的形式是一致的。

      5.属性:和元素节点只是写法上的区别,相当于简化的节点写法

        1)<Father name="爸爸" age="52">...</Father>

        2)<Father name="爸爸" age="52"/>

     二.Unity中XML的存放位置

      1.Resources 只读文件,打包后找不到

      2.Application.streamingAssetsPath 可读,PC端可写,能找到

      3.Application.dataPath 打包后找不到

      4.Application.persistentDataPath 可读可写能找到

    三.Unity中读取xml文件信息

      1.常见的读取方式

        1)XmlDocument:把数据加载到内存中,方便读取

        2)XmlTextReader:以流形式加载数据,内存占用更少,但是单向只读

        3)Linq

      2.使用XmlDocument读取和存储信息的一些方法

        1)LoadXml成员方法:将字符串加载到xml中

        2)Load成员方法:将路径对应的xml文件的内容加载到xml中

        3)SelectSingleNode成员方法:得到单个节点,存储为XmlNode对象,XmlNode中同样有这个成员方法得到节点的单个子节点

        4)节点对象.Attributes[属性名].Value得到属性值,或者节点对象.Attributes.GetNamedItem(属性名).Value可以达到同样的效果

        5)SelectNodes成员方法:得到节点下的所有同名节点,存储为XmlNodeList对象

        6)CreateXmlDeclaration成员方法:创建固定版本和编码信息

        7)AppendChild:把节点对象添加到xml中

        8)CreateElement:创建节点

        9)InnerText属性:节点中存储的信息

        10)SetAttribute成员方法:添加属性

        11)Save成员方法:保存

      3.使用XmlDocument读取和存储信息的一些重要类

        1)XmlNode:读取出的单个节点信息类

        2)XmlNodeList:读取出的多个同名节点信息类存储到一个list中

        3)XmlElement:存储时的单个节点信息类

        4)XmlDeclaration:存储时创建出的xml文件固定版本和编码等信息类

    四.xml序列化和通用保存加载类

      1.xml序列化

        1)序列化:把对象转化为可传输的字节序列过程称为序列化

           反序列化:将字节序列还原为对象的过程称为反序列化

        2)using关键字:using关键字的格式和if类似,都是在后面跟上一个小括号和一个大括号。using关键字后面的小括号中的内容一般是声明一个对象,这个对象需要是继承IDispose接口的对象,在大括号中的代码块调用完毕后,系统会自动调用小括号中对象的Dispose方法将对象释放。一般用于内存占用较大或者读写时操作。

        3)序列化类XmlSerializer和输出流StreamWriter:序列化类的对象相当于一个翻译机器,负责将对象进行序列化翻译,而输出流的对象相当于传送带,负责传输序列化前后的信息。因此,new一个XmlSerializer类对象时需要指定类型(翻译的类的类型),而new一个StreamWriter类对象时需要指定文件地址(传动带的终点),“输入”或者“输出”相当于是说的传送方向(传送带是单向的);使用Serialize方法进行序列化翻译时需要指定流对象(传送带)和要序列化的对象。

        4)示例:

         TestClass test = new TestClass();
            string path = Application.persistentDataPath + "/TestClass.xml";
    
            //尝试创建一个文件流,需要指定文件地址,会自动打开文件(如果有文件直接打开,如果没有文件自动新建一个文件再打开)
            //using括号中声明的对象会在大括号中语句块结束后自动释放
            //using在语句块结束后自动调用对象的Dispose方法(继承IDispose接口),让对象自行销毁
            //一般在内存占用较大或者有读写操作时使用
            using(StreamWriter stream = new StreamWriter(path))
            {
                //序列化对象相当于翻译机器,将对象翻译为序列化文件,需要指定机器能翻译的对象的类型;流相当于传送带,负责运输翻译的对象和结果
                //创建序列化对象,需要指定这个序列化对象的类型
                XmlSerializer xs = new XmlSerializer(typeof(TestClass));
                //调用序列化对象的Serialize方法将对象test通过stream流序列化
                xs.Serialize(stream,test);
            }

        进行序列化的代码。

    public class TestClass
    {
        public int testPublic = 1;
        private int testPrivate = 2;
        protected int testProtected = 3;
        internal int testInternal = 4;
    
        public string testStrPublic = "12";
        public int testPro { get; set; }
    
        public TestClass2 testClass = new TestClass2();
    
    }
    
    public class TestClass2
    {
        public int test1 = 1;
        public float test2 = 2.2f;
        public bool test3 = false;
    }

        被序列化的对象的模板类。

    <?xml version="1.0" encoding="utf-8"?>
    <TestClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <testPublic>1</testPublic>
      <testStrPublic>12</testStrPublic>
      <testClass>
        <test1>1</test1>
        <test2>2.2</test2>
        <test3>false</test3>
      </testClass>
      <testPro>0</testPro>
    </TestClass>

        序列化出来的xml文件内容,可以看到只有public的属性和变量被存储下来了。

      注意:这种序列化方式支持数组、list等,但是不支持dictionary。

        5)使用特性为序列化进行自定义

          [XmlAttribute()]:在类中的属性或变量上加上这个特性,这个属性或变量在序列化时会存储为属性,可以在括号中指定自定义属性名称

          [XmlElement()]:在类中的属性或变量上加上这个特性,这个属性或变量在序列化时存储为节点(默认也是存储为节点),可以在括号中指定自定义节点名称

          [XmlArrayItem()]:在类中的数组属性(变量)前加上这个特性,在括号内传入自定义数组的元素存储为的节点名称

          [XmlArray()]:在类中的list属性(变量)前加上这个特性,在括号内传入自定义的list的元素存储为的节点名称

      2.xml反序列化

        序列化和反序列化的方法是一一对应的,把序列化过程反过来就可以,示例:

            string path = Application.persistentDataPath + "/TestClass.xml";
            TestClass test1 = null;
            using (StreamReader stream = new StreamReader(path))
            {
                XmlSerializer xs = new XmlSerializer(typeof(TestClass));
                test1 = (TestClass)xs.Deserialize(stream);
            }    

        注意:在反序列化时,如果类中声明变量时list类型的变量有默认值,会调用add方法往list中添加值,也就是说反序列化后默认值和反序列化的值都会存储在list变量中,因此尽量不要在创建对象时为list赋初值。

      3.IXmlSerializable接口

        继承IXmlSerializable接口能够自定义类的序列化和反序列化。继承后需要重写方法:

        /// <summary>
        /// 返回结构
        /// </summary>
        /// <returns></returns>
        public XmlSchema GetSchema()
        {
            return null;
        }
    
        /// <summary>
        /// 反序列化时自动调用的方法
        /// </summary>
        /// <param name="reader"></param>
        public void ReadXml(XmlReader reader)
        {
            //读属性
            this.testStrPublic = reader["testStrPublic"];
    
            //读节点
            //方式一:
            //每次reader读取一块内容(一个尖括号的内容或者尖括号包裹的信息),先读取节点开始的尖括号,再读取节点中的内容,再read就继续读取节点结束的尖括号
            reader.Read();
            reader.Read();
            this.testPublic = int.Parse(reader.Value);
            //方式二:
            //循环读取
            while (reader.Read())
            {
                //判断读取出的类型,是节点开始标签(XmlNodeType.Element)、节点中包裹的内容(XmlNodeType.Text)还是节点结束标签(XmlNodeType.EndElement),根据读取出的类型作处理
                if (reader.NodeType == XmlNodeType.Text)
                {
                    //Name属性是节点的名称,根据节点名称作响应的处理
                    switch (reader.Name)
                    {
                        case "testPublic":
                            break;
                    }
                }
            }
    
            //读包裹节点
            XmlSerializer xs = new XmlSerializer(this.testStrPublic.GetType());
            //跳过根节点
            reader.Read();
            reader.ReadStartElement("testStrPublic");
            this.testStrPublic = (string)xs.Deserialize(reader);
            reader.ReadEndElement();
        }
    
        /// <summary>
        /// 序列化时自动调用的方法
        /// </summary>
        /// <param name="writer"></param>
        public void WriteXml(XmlWriter writer)
        {
            //写属性
            writer.WriteAttributeString("testStrPublic", this.testStrPublic);
    
            //写节点
            writer.WriteElementString("testStrPublic", this.testStrPublic);
    
            //写包裹节点
            writer.WriteStartElement("testStrPublic");
            XmlSerializer xs = new XmlSerializer(this.testStrPublic.GetType());
            xs.Serialize(writer,this.testStrPublic);
            writer.WriteEndElement();
        }

      4.让Dictionary支持xml序列化和反序列化

        只需要重写一个继承Dictionary的类,这个类再实现IXmlSerializable接口,重写方法即可。

    public class SerializerDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
    {
        public XmlSchema GetSchema()
        {
            return null;
        }
    
        public void ReadXml(XmlReader reader)
        {
            XmlSerializer keyXS = new XmlSerializer(typeof(TKey));
            XmlSerializer valueXS = new XmlSerializer(typeof(TValue));
            //跳过根节点
            reader.Read();
            //没有到根节点的结束尖括号,就可以一直读取
            while(reader.NodeType != XmlNodeType.EndElement)
            {
                TKey key = (TKey)keyXS.Deserialize(reader);
                TValue value = (TValue)valueXS.Deserialize(reader);
                this.Add(key, value);
            }
        }
    
        public void WriteXml(XmlWriter writer)
        {
            XmlSerializer keyXS = new XmlSerializer(typeof(TKey));
            XmlSerializer valueXS = new XmlSerializer(typeof(TValue));
            foreach(KeyValuePair<TKey,TValue> pair in this)
            {
                keyXS.Serialize(writer, pair.Key);
                valueXS.Serialize(writer, pair.Value);
            }
        }
    }

      5.xml管理类

    public class XmlDataManager
    {
        //单例模式模块
        private static XmlDataManager instance;
        public static XmlDataManager Instance
        {
            get
            {
                if (instance == null)
                    instance = new XmlDataManager();
                return instance;
            }
        }
        private XmlDataManager() { }
    
        /// <summary>
        /// 数据存储类
        /// </summary>
        /// <param name="data">存储的数据对象</param>
        /// <param name="fileName">文件名</param>
        public void SaveData(object data,string fileName)
        {
            string path = Application.persistentDataPath + "/" + fileName + ".xml";
            using(StreamWriter writer = new StreamWriter(path))
            {
                XmlSerializer xs = new XmlSerializer(data.GetType());
                xs.Serialize(writer, data);
            }
        }
    
        /// <summary>
        /// 加载对象
        /// </summary>
        /// <param name="type">对象类型</param>
        /// <param name="fileName">文件名称</param>
        /// <returns></returns>
        public object LoadData(Type type,string fileName)
        {
            string path = Application.persistentDataPath + "/" + fileName + ".xml";
            if (!File.Exists(path))
            {
                path = Application.persistentDataPath + "/" + fileName + ".xml";
                if (!File.Exists(path))
                {
                    return Activator.CreateInstance(type);
                }
            }
            object result = null;
            using(StreamReader reader = new StreamReader(path))
            {
                XmlSerializer xs = new XmlSerializer(type);
                result = xs.Deserialize(reader);
            }
            return result;
        }
    }
  • 相关阅读:
    XP显示桌面
    批量改名
    poj 3126 BFS
    poj 3278 BFS
    poj 1426 BFS
    准备打酱油…
    POJ 2243 BFS 和 简单的调试方法学习
    K
    EXCEL fundamentals
    poj 1011 DFS+剪枝
  • 原文地址:https://www.cnblogs.com/movin2333/p/14599217.html
Copyright © 2011-2022 走看看