1早期的数据格式
在早期程序开发中一个简单且常用的数据格式为CSV。该格式单纯依靠逗号来分割数据。目前windows的office依然支持CSV解析,我们可以试着新建一个txt文件,在里面加入逗号分隔的信息:
a, 1, 15, 30, true
将txt文件后缀改为csv,可以看到系统自动生成了一个excel表格,由空格分隔的每一项都成了表格的一个单元。但显然这种方法可读性很差,因此对于存储大量数据不常用
2 json
json是一种“数组+对象” 的数据存储方式,其中[ ]内为数组,{ }内为对象,例如
{"Persons":[{"name":"a","age":18},{"name":"b","age":17}]
}
unity自带json数据创建和解析的功能JsonUtility。
示例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;[Serializable]
public class Person {public string name;public int age;
}[Serializable]
public class Persons {public Person[] persons;
}public class JsonUtilityTest : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){Person person = new Person();person.name = "a";person.age = 18;Person person2 = new Person();person2.name = "b";person2.age = 17;Persons persons = new Persons();persons.persons = new Person[] {person, person2};string jsonStr = JsonUtility.ToJson(persons);Debug.Log(jsonStr);Persons ps = JsonUtility.FromJson<Persons>(jsonStr);foreach (Person p in ps.persons) {Debug.Log(p.name);}}}
1
using System;
要使用JsonUtility工具,要先在文件中引入System
2
[Serializable]
public class Person {public string name;public int age;
}[Serializable]
public class Persons {public Person[] persons;
}
这里我们创建两个类Person和Persons用于示例。在类前面的标记[Serializable]代表可序列化,只有带有该标记的类才能转化为json格式
3
string jsonStr = JsonUtility.ToJson(persons);
在我们创建并赋值Persons对象后,使用JsonUtility.ToJson()方法即可将对象自动转化为json文件,其内容如下:
{“persons”:[{“name”:“a”,“age”:18},{“name”:“b”,“age”:17}]}
Persons ps = JsonUtility.FromJson<Persons>(jsonStr);
要解析json文件,我们使用方法JsonUtility.FromJson<类型>()得到json文件最外层的数据类型,然后即可对该数据进行层层拆包得到里面的数据
除了系统自带的JsonUtility方法,还有很多常用的第三方json数据处理方法,如LitJson
下载LitJson的dll文件后,在unity Assets文件夹下面创建Plugins文件夹,并把LitJson.dll放入该文件夹。在C#脚本中引入LitJson即可使用LitJson文件
LitJson使用示例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;public class Heros {public Hero[] heros;
}public class Hero {public string name;public int age;
}public class TestLitJson : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){fun3();}void fun1() {Hero hero1 = new Hero();hero1.name = "Superman";hero1.age = 35;Hero hero2 = new Hero();hero2.name = "Batman";hero2.age = 38;Heros heros = new Heros();heros.heros = new Hero[] {hero1, hero2};string jsonStr = JsonMapper.ToJson(heros);Debug.Log(jsonStr);Heros hs = JsonMapper.ToObject<Heros>(jsonStr);Debug.Log(hs.heros[1].name);}// using JsonData typevoid fun2() {JsonData jd1 = new JsonData();jd1.SetJsonType(JsonType.Object);jd1["name"] = "Superman";jd1["age"] = 35;JsonData jd2 = new JsonData();jd2.SetJsonType(JsonType.Object);jd2["name"] = "Batman";jd2["age"] = 38;JsonData jds = new JsonData();jds.SetJsonType(JsonType.Array);jds.Add(jd1);jds.Add(jd2);JsonData heroJd = new JsonData();heroJd.SetJsonType(JsonType.Object);heroJd["heros"] = jds;Debug.Log(heroJd.ToJson());}void fun3() {string jsonStr = "{'heros':[{'name':'Superman','age':35},{'name':'Batman','age':38}]}";JsonData herosJd = JsonMapper.ToObject(jsonStr);JsonData heros = herosJd["heros"];foreach (JsonData heroJd in heros) {Debug.Log(heroJd["name"].ToString() + " " + (int)heroJd["age"]);}}
}
1
void fun1() {Hero hero1 = new Hero();hero1.name = "Superman";hero1.age = 35;Hero hero2 = new Hero();hero2.name = "Batman";hero2.age = 38;Heros heros = new Heros();heros.heros = new Hero[] {hero1, hero2};string jsonStr = JsonMapper.ToJson(heros);Debug.Log(jsonStr);Heros hs = JsonMapper.ToObject<Heros>(jsonStr);Debug.Log(hs.heros[1].name);}
和JsonUtility类似,LitJson可以根据一个类创建json文件,使用JsonMapper.ToJson文件
要解析Json文件,使用JsonMapper.ToObject方法,可得到Json文件解析后的对象
2
// using JsonData typevoid fun2() {JsonData jd1 = new JsonData();jd1.SetJsonType(JsonType.Object);jd1["name"] = "Superman";jd1["age"] = 35;JsonData jd2 = new JsonData();jd2.SetJsonType(JsonType.Object);jd2["name"] = "Batman";jd2["age"] = 38;JsonData jds = new JsonData();jds.SetJsonType(JsonType.Array);jds.Add(jd1);jds.Add(jd2);JsonData heroJd = new JsonData();heroJd.SetJsonType(JsonType.Object);heroJd["heros"] = jds;Debug.Log(heroJd.ToJson());}
除了利用对象创建Json文件,LitJson还支持不创建对象,直接使用JsonData创建Json文件。JsonData类型包括了Int Double Boolean Array Object等常用类型。
在上面代码中,我们创建JsonData类jd1,之后使用SetJsonType将其类型设为Object(这一句可以省略,LitJson会自动判断数据类型)。
对于Object类,使用键值对来添加值,对于数组,使用Add方法添加元素
void fun3() {string jsonStr = "{'heros':[{'name':'Superman','age':35},{'name':'Batman','age':38}]}";JsonData herosJd = JsonMapper.ToObject(jsonStr);JsonData heros = herosJd["heros"];foreach (JsonData heroJd in heros) {Debug.Log(heroJd["name"].ToString() + " " + (int)heroJd["age"]);}}
JsonMapper.ToObject方法除了支持使用泛型将Json数据解析成特定类型,还可以不使用泛型,解析完的数据默认类型全部为JsonData类型,包括内部的所有类的数据。因此在Debug.Log中我们要先将name和age分别转换为String和int类型
2 xml
xml是一种常用的标记语言,语法和html很类似,都由节点组成。我们以下面例子来讲解
<?xml version="1.0" encoding="utf-8"?>
<root><heros><hero id="1"><name>Superman</name><age>35</age></hero><hero id="2"><name>Batman</name><age>37</age></hero><hero id="3"><name>Spiderman</name><age>30</age></hero></heros>
</root>
1
<?xml version="1.0" encoding="utf-8"?>
这一句用于声明xml格式,标明版本和使用编码
2
<root></root>
为根节点,根节点只能有一个。其他所有节点在根节点内部。
3 <hero id="1"> <name>Superman</name> <age>35</age> </hero>
对于一个节点,里面要么保存字符串值,要么保存一个子节点(不可同时保存)。节点尖括号内部可以添加属性(即为节点变量),属性值必须包括在""里面
解析xml文件(方法1)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Xml;public class XMLTest : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){parseXml();}void parseXml() {// xml文档类XmlDocument doc = new XmlDocument();doc.Load(Application.dataPath + "/XML/testXml.xml");// rootXmlElement rootEle = doc.LastChild as XmlElement; // herosXmlElement herosEle = rootEle.FirstChild as XmlElement;// heorforeach(XmlElement heroEle in herosEle.ChildNodes) {string id = heroEle.GetAttribute("id");string name = heroEle.ChildNodes[0].InnerText;string age = heroEle.ChildNodes[1].InnerText;Debug.Log(id + name + age);}}
}
在文件开头要引入System.Xml以使用xml工具
xml文件类型称为XmlDocument。我们先创建新的XmlDocument对象并导入刚才创建的xml文件
LastChild FirstChild方法用于获取节点的第一个和最后一个元素。ChildNodes数组保存节点里面所有元素。获取到的元素类型XmlNode,该类型为XmlElement的子类,因此获取到XmlElement需要进行类型转换
GetAttribute方法用于获取节点内的属性。要得到节点内保存的值使用方法InnerText
解析xml文件(方法2)
void parseXml2() {XmlDocument doc = new XmlDocument();doc.Load(Application.dataPath + "/XML/testXml.xml");XmlNodeList list = doc.SelectNodes("/root/heros/hero/name");foreach (XmlElement element in list) {Debug.Log(element.InnerText);}}
除了常规从根目录进行解析,我们可以实现XPath直接通过文件路径访问到特定的节点。在上面例子中,SelectNodes()根据给出的XPath路径找到所有符合该路径的节点,得到结果Superman,Batman,Spiderman
XPath路径还有几种特殊写法
1 相对路径
XmlNodeList list = doc.SelectNodes(“//name”);
//代表使用相对路径。此时我们会查找到所有名为name的节点。不过直接使用相对路径查找要遍历所有节点,效率较低
2 访问第几个节点
XmlNodeList list = doc.SelectNodes(“//heros/hero[last()-1]/name”)
在节点后面[ ]中可以输入要访问第几个节点,注意第一个节点编号为1不是0.last()为最后一个节点的编号
3 访问前几个节点
XmlNodeList list = doc.SelectNodes(“//heros/hero[position()< 3]/name”);
在[ ]中position()可以用于访问前几个节点,上面的position()< 3代表访问1,2节点
4 根据节点属性值访问节点
XmlNodeList list = doc.SelectNodes(“//heros/hero[@id=2]/name”);
在[ ]中@id=2代表访问所有有id属性的节点中,id值为2的节点。如果直接为@id代表访问所有有id属性的节点
构建XML文件
void createXml() {XmlDocument doc = new XmlDocument();XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", "");doc.AppendChild(dec);XmlElement rootEle = doc.CreateElement("root");doc.AppendChild(rootEle);XmlElement herosEle = doc.CreateElement("heros");rootEle.AppendChild(herosEle);string[] names = new string[] {"Superman", "Batman", "Spiderman"};string[] ages = new string[] {"35", "37", "20"};for (int i = 0; i < 3; i++) {XmlElement heroEle = doc.CreateElement("hero");herosEle.AppendChild(heroEle);XmlElement nameEle = doc.CreateElement("name");nameEle.InnerText = names[i];heroEle.AppendChild(nameEle);XmlElement ageEle = doc.CreateElement("age");ageEle.InnerText = ages[i];heroEle.AppendChild(ageEle);XmlAttribute id = doc.CreateAttribute("id");id.Value = i + "";heroEle.Attributes.Append(id);}doc.Save(Application.dataPath + "/XML/test2.xml");}
1
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", "");
这一句用于创建XML声明,也就是XML文件开头的<?xml version="1.0" encoding="utf-8"?>
2
XmlElement rootEle = doc.CreateElement("root");
doc.AppendChild(rootEle);
创建根节点名称root,并在文件根目录添加改节点。后面添加节点的语句写法相同
3
XmlElement nameEle = doc.CreateElement("name");
nameEle.InnerText = names[i];
heroEle.AppendChild(nameEle);
对有内容的节点,使用InnerText来填充内容,再把该节点加入到其父节点。
4
XmlAttribute id = doc.CreateAttribute("id");
id.Value = i + "";
heroEle.Attributes.Append(id);
要为一个节点添加属性,首先创建XmlAttribute对象,再把该对象加入节点的Attribute中,方法和添加子节点类似
5
doc.Save(Application.dataPath + "/XML/test2.xml");
保存XML文件到指定路径