1. 程式人生 > >XML與JSON在unity中的應用

XML與JSON在unity中的應用

最近在學習資料持久化的時候瞭解到了XML和JSON兩種儲存資料的格式,在這裡簡單的做一下分享。如有錯誤,歡迎指正!

unity中的資料持久化方式

unity中資料持久的方式有很多種,最簡單的便是Playerfabs這個類,這個類可以去官方文件檢視,不多介紹。Playerfabs的API

什麼是XML與JSON

  1. XML

XML是擴充套件標記語言 (Extensible Markup Language) ,用於標記電子檔案使其具有結構性的標記語言,可以用來標記資料、定義資料型別,是一種允許使用者對自己的標記語言進 行定義的源語言。 XML是標準通用標記語言 (SGML) 的子集,非常適合 Web 傳輸。XML 提供統一的方法來描述和交換獨立於應用程式或供應商的結構化資料。

優點:格式統一,符合標準;.容易與其他系統進行遠端互動,資料共享比較方便。

缺點:XML檔案龐大,檔案格式複雜,傳輸佔頻寬;伺服器端和客戶端解析XML花費較多的資源和時間;需要花費大量程式碼來解析XML;

  2. JSON

JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式,易於人閱讀和編寫。同時也易於機器解析和生成。JSON採用完全獨立於語言的文字格式,但是也使用了類似於C語言家族的習慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 這些特性使JSON成為理想的資料交換語言。

優點:資料格式比較簡單,易於讀寫,格式都是壓縮的,佔用頻寬小;.支援多種語言;

缺點:可讀性較xml略差;

總結:它們其實就是兩種資料儲存與傳輸的格式,主要用於配置檔案,描述資料,儲存資料,資料傳輸等。

他們的使用

  1. XML

  • 一段簡單的XML程式碼
<?xml version="1.0" encoding="utf-8"?>
<Studio xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>memo</Name>
  <Number>3</Number>
  <Members>
    <Member>
      <Name>liu</Name>
      <Sex>男</Sex>
      <MajorClass>電子資訊</MajorClass>
      <Vocation>策劃</Vocation>
    </Member>
    <Member>
      <Name>li</Name>
      <Sex>男</Sex>
      <MajorClass>軟體工程</MajorClass>
      <Vocation>程式</Vocation>
    </Member>
    <Member>
      <Name>sun</Name>
      <Sex>男</Sex>
      <MajorClass>軟體工程</MajorClass>
      <Vocation>程式</Vocation>
    </Member>
  </Members>
</Studio>
  • 在unity中用程式碼生成這個檔案
        using System.Xml;
        public static void Creat()
        {       
            if(!File.Exists(path))
            {
                Debug.Log(path);
                //建立xml檔案例項
                XmlDocument xmlDoc = new XmlDocument();
    
                //建立根節點並新增屬性
                XmlElement root = xmlDoc.CreateElement("Studio");
                root.SetAttribute("Name","memo");            
    
                //繼續建立下層節點並且設定節點中的數值
                XmlElement member = xmlDoc.CreateElement("Member");
                XmlElement name = xmlDoc.CreateElement("Name");
                name.InnerText = "liu";
                XmlElement sex = xmlDoc.CreateElement("Sex");
                sex.InnerText = "男";
                XmlElement vocation = xmlDoc.CreateElement("Vocation");
                vocation.InnerText = "策劃";
                XmlElement majorClass = xmlDoc.CreateElement("MajorClass");
                majorClass.InnerText = "電子資訊";       
                member.AppendChild(name);
                member.AppendChild(sex);
                member.AppendChild(vocation);
                member.AppendChild(majorClass);
                root.AppendChild(member);
    
                member = xmlDoc.CreateElement("Member");
                name = xmlDoc.CreateElement("Name");
                name.InnerText = "li";
                sex = xmlDoc.CreateElement("Sex");
                sex.InnerText = "男";
                vocation = xmlDoc.CreateElement("Vocation");
                vocation.InnerText = "程式";
                majorClass = xmlDoc.CreateElement("MajorClass");
                majorClass.InnerText = "軟體工程";
                member.AppendChild(name);
                member.AppendChild(sex);
                member.AppendChild(vocation);
                member.AppendChild(majorClass);
                root.AppendChild(member);
    
                member = xmlDoc.CreateElement("Member");
                name = xmlDoc.CreateElement("Name");
                name.InnerText = "sun";
                sex = xmlDoc.CreateElement("Sex");
                sex.InnerText = "男";
                vocation = xmlDoc.CreateElement("Vocation");
                vocation.InnerText = "程式";
                majorClass = xmlDoc.CreateElement("MajorClass");
                majorClass.InnerText = "軟體工程16級";
                member.AppendChild(name);
                member.AppendChild(sex);
                member.AppendChild(vocation);
                member.AppendChild(majorClass);
                root.AppendChild(member);
    
                //將根節點儲存到例項中而後將xml檔案儲存到本地
                xmlDoc.AppendChild(root);
                xmlDoc.Save(path);
            }
    
        }
  • 更新這個檔案
        public static void UpdatePerson(string name, string newType, string newData)
        {
            if (File.Exists(path))
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(path);
                XmlNodeList members = xmlDoc.SelectNodes("//Member");
                foreach(XmlNode member in members)
                {
                    if (member.SelectSingleNode("Name").InnerText.Equals(name))
                    {
                        XmlNode data = member.SelectSingleNode(newType);
                        data.InnerText = newData;
                        break;
                    }
                }
            }
        }
  • 增加XML節點
        public static void InsertPerson(string name, string sex, string majorClass, string vocation)
        {
            if (File.Exists(path))
            {
                XmlDocument xmlDoc = new XmlDocument();
                //讀取xml檔案
                xmlDoc.Load(path);
                //selectSingleNode()只能找子節點不能找孫節點,可用SelectSingleNode("//Studio")找孫節點
                XmlNode root = xmlDoc.SelectSingleNode("Studio");
    
                XmlElement member = xmlDoc.CreateElement("Member");
                XmlElement xmlName = xmlDoc.CreateElement("Name");
                xmlName.InnerText = name;
                XmlElement xmlSex = xmlDoc.CreateElement("Sex");
                xmlSex.InnerText = sex;
                XmlElement xmlVocation = xmlDoc.CreateElement("Vocation");
                xmlVocation.InnerText = vocation;
                XmlElement xmlMajorClass = xmlDoc.CreateElement("MajorClass");
                xmlMajorClass.InnerText = majorClass;
    
                //給隊員新增屬性而後將隊員加入團隊
                member.AppendChild(xmlName);
                member.AppendChild(xmlSex);
                member.AppendChild(xmlVocation);
                member.AppendChild(xmlMajorClass);
                root.AppendChild(member);
    
                xmlDoc.Save(path);
    
            }
        }
  • 刪除XML節點
        public static void DeletePerson(string name)
        {
            if (File.Exists(path))
            {
                XmlDocument xmlDoc = new XmlDocument();
                //讀取xml檔案
                xmlDoc.Load(path);
                //selectSingleNode()只能找子節點不能找孫節點,可用SelectSingleNode("//Studio")找孫節點
                XmlNode root = xmlDoc.SelectSingleNode("Studio");
                XmlNodeList members = root.SelectNodes("Member");
                //XmlNode[] reslt = members.Cast<XmlNode>().Where((node) => { return node["Name"].InnerText.Equals(name); }).ToArray();
                foreach (XmlNode member in members)
                {
                    if(member.SelectSingleNode("Name").InnerText.Equals(name))
                    {
                        root.RemoveChild(member);
                    }
                }
                xmlDoc.Save(path);
            }
        }
  • 解析這個檔案
        public static void LoadPerson()
        {
            if (File.Exists(path))
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(path);
                XmlElement studio = xmlDoc.SelectSingleNode("Studio") as XmlElement;
                XmlNodeList members = studio.SelectNodes("Member");
                Debug.Log(studio.GetAttribute("Name") + " studio 有" + members.Count + "名成員,分別是:");
                int i = 0;
                foreach(XmlNode member in members)
                {
                    i++;
                    XmlNode name = member.SelectSingleNode("Name");
                    XmlNode sex = member.SelectSingleNode("Sex");
                    XmlNode Vocation = member.SelectSingleNode("Vocation");
                    XmlNode majorClass = member.SelectSingleNode("MajorClass");
                    Debug.Log(i + "、姓名:" + name.InnerText + ",性別:" + sex.InnerText + ",職務:" + Vocation.InnerText + ",專業:" + majorClass.InnerText);
                }
                xmlDoc.Save(path);
            }
        }

  2. JSON

  • 一段簡單的JSON程式碼
    {
      "Name": "memo",
      "Number": 3,
      "Members": [
        {
          "Name": "liu",
          "Sex": "男",
          "MajorClass": "電子資訊",
          "Vocation": "策劃"
        },
        {
          "Name": "li",
          "Sex": "男",
          "MajorClass": "軟體工程",
          "Vocation": "程式"
        },
        {
          "Name": "sun",
          "Sex": "男",
          "MajorClass": "軟體工程",
          "Vocation": "程式"
        }
      ]
    }
  • 在unity中用程式碼生成這個檔案

這裡使用了litjson,關於litjson的使用:litjson

    using LitJson;
    public static void Creat(string json)
    {
        if(!File.Exists(path))
        {
            StreamWriter sw = new StreamWriter(path);
            StringBuilder sb = new StringBuilder();
            JsonWriter jw = new JsonWriter(sb);

            //相當於寫下了"{"
            jw.WriteObjectStart();

            jw.WritePropertyName("Name");
            jw.Write("memo");

            jw.WritePropertyName("Number");
            jw.Write(3);

            jw.WritePropertyName("Member");
            //相當於寫下了"["
            jw.WriteArrayStart();

            jw.WriteObjectStart();
            jw.WritePropertyName("Name");
            jw.Write("liu");
            jw.WritePropertyName("Sex");
            jw.Write("男");
            jw.WritePropertyName("Vocation");
            jw.Write("策劃");
            jw.WritePropertyName("MajorClass");
            jw.Write("電子資訊");            
            jw.WriteObjectEnd();

            jw.WriteObjectStart();
            jw.WritePropertyName("Name");
            jw.Write("li");
            jw.WritePropertyName("Sex");
            jw.Write("男");
            jw.WritePropertyName("Vocation");
            jw.Write("程式");
            jw.WritePropertyName("MajorClass");
            jw.Write("軟體工程");
            jw.WriteObjectEnd();

            jw.WriteObjectStart();
            jw.WritePropertyName("Name");
            jw.Write("sun");
            jw.WritePropertyName("Sex");
            jw.Write("男");
            jw.WritePropertyName("Vocation");
            jw.Write("程式");
            jw.WritePropertyName("MajorClass");
            jw.Write("軟體工程");
            jw.WriteObjectEnd();

            //相當於寫下了"]"
            jw.WriteArrayEnd();
            //相當於寫下了"}"
            jw.WriteObjectEnd();

            sw.Write(sb.ToString());
            sw.Close();
        }
    }
  • JSON的更新
        public static void UpdatePerson(string name, string newType, string newData)
        {
            if (File.Exists(path))
            {
                string str = File.ReadAllText(path);
                JsonData jd = JsonMapper.ToObject(str);
                JsonData jd1 = jd["Member"];
                foreach(JsonData vjd in jd1)
                {
                    if(((string)vjd["Name"]).Equals(name))
                    {
                        vjd[newType] = newData;
                        jd["Member"] = jd1;
                        break;
                    }
                }
                File.WriteAllText(path, jd.ToJson());
            }
        }
  • JSON的增加
        public static void InsertPerson(string name, string sex, string majorClass, string vocation)
        {
            if (File.Exists(path))                                                                                                                      
            {
                string str = File.ReadAllText(path);
                JsonData jd = JsonMapper.ToObject(str);
                JsonData jd1 = jd["Member"];
    
                JsonData jd2 = new JsonData();
                jd2["Name"] = name;
                jd2["Sex"] = sex;
                jd2["MajorClass"] = majorClass;
                jd2["Vocation"] = vocation;
                jd1.Add(jd2);
                jd["Number"] = jd1.Count;
                jd["Member"] = jd1;
                File.WriteAllText(path, jd.ToJson());
            }
        }
  • JSON的刪除
        public static void DeletePerson(string name)
        {
            if (File.Exists(path))
            {
                string str = File.ReadAllText(path);
                JsonData jd = JsonMapper.ToObject(str);
                JsonData jd1 = jd["Member"];
    
                foreach(JsonData vjd in jd1)
                {
                    if(((string)vjd["Name"]).Equals(name))
                    {
                        ((IList)jd1).Remove(vjd);
                        jd["Member"] = jd1;
                        break;
                    }
                }
    
                File.WriteAllText(path, jd.ToJson());
            }
        }
  • 解析這個檔案
        public static void LoadPerson()
        {
            if (File.Exists(path))
            {
                StreamReader sr = new StreamReader(path);
                string str = sr.ReadToEnd();
                JsonData jd = JsonMapper.ToObject(str);
    
                Debug.Log(jd["Name"] + " studio 有" + jd["Number"] + "名成員,分別是:");
                int i = 0;
                foreach(JsonData vjd in jd["Member"])
                {
                    i++;
                    Debug.Log(i + "、姓名:" + (string)vjd["Name"] + ",性別:" + (string)vjd["Sex"] + ",職務:" + (string)vjd["Vocation"] + ",專業:" + (string)vjd["MajorClass"]);
                }
            }
        }

他們的序列化與反序列化

序列化 (Serialization)是將物件狀態轉換為可保持或傳輸的格式的過程。在序列化期間,物件將其當前狀態寫入到臨時或永續性儲存區。以後,可以通過從儲存區中讀取或反序列化物件的狀態,重新建立該物件。

與序列化相對的是反序列化,它將流轉換為物件。這兩個過程結合起來,可以輕鬆地儲存和傳輸資料。這就是序列化的意義所在。

要序列化的類

public class Member  {

    public string Name { get; set; }
    public string Sex { get; set; }
    public string MajorClass { get; set; }
    public string Vocation { get; set;}

    public Member(string name,string sex,string majorClass,string vocation)
    {
        Name = name;
        Sex = sex;
        MajorClass = majorClass;
        Vocation = vocation;
    }

    public Member()
    {
        Name = "liu";
        Sex = "男";
        MajorClass = "電子資訊";
        Vocation = "策劃";
    }
}

public class Studio{

    public string Name { get; set; }
    public int Number { get; set; }
    public Member[] Members { get; set; }


    public Studio(string name, Member[] members)
    {
        Name = name;
        Members = members;
        Number = members.Length;
    }

    public Studio()
    {
        Name = "memo";
        Members = new Member[3];
        Members[0] = new Member("liu", "男", "電子資訊", "策劃");
        Members[1] = new Member("li", "男", "軟體工程", "程式");
        Members[2] = new Member("sun", "男", "軟體工程", "程式");
        Number = Members.Length;
    }
}

  1. XML

    using System.Xml.Serialization;
    public static void CreatXML()
    {
        Studio studio = new Studio();
        if (!File.Exists(path))
        {
            StreamWriter sw = new StreamWriter(path);
            XmlSerializer ser = new XmlSerializer(typeof(Studio));
            ser.Serialize(sw, studio);
            sw.Close();
        }
    }

  2. JSON

    
    public static void CreatJson()
    {
        Studio studio = new Studio();
        if (!File.Exists(path))
        {
            StreamWriter sw = new StreamWriter(path);
            string s = JsonMapper.ToJson(studio);
            sw.Write(s);
            sw.Close();
        }
    }

關於路徑

Application類中一共提供了四個路徑:dataPath、persistentDataPath、streamingAssetsPath、 temporaryCachePath(均為只讀屬性)

屬性名稱 含義 Unity Editor返回路徑
Application.dataPath 此屬性用於返回程式的資料檔案所在資料夾的路徑。 Application(工程目錄)/Assets
Application.streamingAssetsPath 此屬性用於返回流資料的快取目錄,返回路徑為相對路徑,適合設定一些外部資料檔案的路徑。 Application(工程目錄)/Assets/StreamingAssets
Application.persistentDataPath 此屬性用於返回一個持久化資料儲存目錄的路徑,可以在此路徑下儲存一些持久化的資料檔案。 C:/Users/username/AppData/LocalLow/company/工程名
Application.temporaryCachePath 此屬性用於返回一個臨時資料的快取目錄。 C:/Users/username/AppData/Local/Temp/company/工程名

dataPath 和 stremingAssetsPath是相對於程式的安裝目錄的路徑,非常適用於移植平臺設定外部資料檔案讀取路徑。

persistentDataPath和temporaryCachePath返回的程式所在平臺的固定位置,適用於儲存程式執行過程中一些用於持久化的資料。