Unity数据持久化-XML
XML(可扩展标记语言)被设计用来“结构化”传输和存储数据,携带数据和交换数据
XML文档即文本文件,按照XML语法规则书写,本质也是String
文档必须包含根元素。该元素是所有其他元素的父元素! XML文档中的元素形成了一颗文档树。这棵树丛根部开始,并扩展 (所有元素都可拥有子元素)
XML非常适合 Web 传输,提供了统一的方法来描述和交换独立于应用程序或供应商的结构化数据
容易与其他系统进行远程交互,数据共享比较方便
xmlDocument类位于System.Xml中 ,专门解析XML文档
xmlDocument.Save(“XXX”)方法:保存XML文档到XXX路径
xmlDocument.Load(“XXX”)方法:选择要【加载】解析的XML文档的名字
xmlElement.InnerText:获取节点内部的文本信息
XML写入流程:
创建根节点
每组数据创建一个节点
将创建的节点 加入的根节点中
保存:
如果文件不存在会自动创建文件
注意,存储只能是 string类型的数据,如果不是,就要转为string。
特殊:如果是字典和列表的存储,同理,只能按数据一个一个转为string存储,不能直接存字典和列表:
XmlElement Cnode1 = xmlDocument.CreateElement("Cnode1");
Cnode1.InnerText = save.c[0][0];
Cnode1.SetAttribute("Cnode2", save.c[1][2]); //前一个是list列表第二个元素,后一个是字典中int 所对应的2的内容:e.Add(2, "@#$%^&*()");
Cnode1.SetAttribute("Cnode3", "这是同一个Cnode1节点下的数据");
root.AppendChild(Cnode1);
//Cnode1.InnerText = save.c[0][1];使用InnerText如果不创建同名节点,会在同节点下覆盖内容
//root.AppendChild(Cnode1);
Cnode1 = xmlDocument.CreateElement("Cnode1");
Cnode1.InnerText = save.c[0][1];
root.AppendChild(Cnode1);
Cnode1 = xmlDocument.CreateElement("Cnode1");
Cnode1.InnerText = "这是同名Cnode1节点下的数据";
root.AppendChild(Cnode1);
最后将根节点加入到xmlDocument,并使用Save方法存储:
读取方法:
1.先判断路径是否存在:
2.建立XmlDocument,使用XmlDocument,Load方法读取
3.通过名字得到所有同名节点,并按先后顺序返回一个集合
使用过程注意事项:
创建的一个节点,可以有多个属性,在同一个节点下创建的多个属性,也可以读取,
同名节点数据添加:每一次都要创建一个节点,CreateElement(可同名,同名当读取时会按顺序返回一个列表)
同一个节点数据添加:使用SetAttribute
最终存储为:
读取同名节点:
///同名节点读取
XmlNodeList cLoad = xmlDocument.GetElementsByTagName("Cnode1");
//读取所有名为Cnode1的节点
d.Add(0, cLoad[0].InnerText);//添加一个字典
d.Add(1, cLoad[1].InnerText);
//save.c.Add(d); 同一个字典添加两次 会在list 里面有两个这个字典(序号不同)
save.c.Add(d);
//save.c.Add(d); 不要将改过的字典再次添加(会再次添加改过后的字典),应该直接通过list的【】调用对应字典的add方法
save.c[0].Add(2, cLoad[2].InnerText);
读取同一个节点的不同属性:
///同一个节点,读取属性
//XmlAttributeCollection XmlAttributeCollection = cLoad[0].Attributes;
//XmlNode xmlNode = XmlAttributeCollection.GetNamedItem("Cnode1");//读取属性,不能读取未添加的属性,即节点名不等于属性名,例如Cnode1
//e.Add(0, xmlNode.InnerText);
XmlAttributeCollection XmlAttributeCollection1 = cLoad[0].Attributes;
XmlNode xmlNode1 = XmlAttributeCollection1.GetNamedItem("Cnode2");//要根据属性的name值 读取
e.Add(1, xmlNode1.InnerText);
XmlAttributeCollection XmlAttributeCollection2 = cLoad[0].Attributes;
XmlNode xmlNode2 = XmlAttributeCollection2.GetNamedItem("Cnode3");
e.Add(2, xmlNode2.InnerText);
save.c.Add(e);
读取示例:
private static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//SaveByXML();
Save save = LoadByXML();
Console.WriteLine(save.a);
Console.WriteLine(save.b);
Console.WriteLine(save.c[0][0]);//取列表第一个字典d的 键值整数0 对应的string
Console.WriteLine(save.c[0][1]);
Console.WriteLine(save.c[0][2]);
//Console.WriteLine(save.c[1][0]);//取列表第二个字典e的 键值整数0 对应的string
Console.WriteLine(save.c[1][1]);
Console.WriteLine(save.c[1][2]);
}
总结:
同名节点创建复杂,但是读取直接返回list,方便读取
同一个节点根据name写入多个数据,写入方便,不用频繁创建节点,但是读取复杂,每一个数据读取都要创建 XmlAttributeCollection 和 XmlNode 。
完整代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml;
namespace 序列化反序列化
{
[Serializable]
public class Save
{
public int a;
public string b;
public List<Dictionary<int, string>> c = new List<Dictionary<int, string>>();
}
internal class Program
{
public static Dictionary<int, string> d = new Dictionary<int, string>();
public static Dictionary<int, string> e = new Dictionary<int, string>();
private static void Main(string[] args)
{
Console.WriteLine("Hello World!");
//SaveByXML();//保存方法
Save save = LoadByXML();//读取方法
Console.WriteLine(save.a);
Console.WriteLine(save.b);
Console.WriteLine(save.c[0][0]);//取列表第一个字典的 键值整数0 对应的string
Console.WriteLine(save.c[0][1]);
Console.WriteLine(save.c[0][2]);
//Console.WriteLine(save.c[1][0]);//此节点没有和节点名相同的属性名,因此不存在Cnode1属性的数据
Console.WriteLine(save.c[1][1]);
Console.WriteLine(save.c[1][2]);
}
public static Save initDate()
{
Save save = new Save();
save.a = 18;
save.b = "Hello Save";
d.Add(0, "这是一个键值为0的字典的内容");
d.Add(1, "This is the contents of a dictionary with a key value of 1");
e.Add(2, "@#$%^&*()");
save.c.Add(d);
save.c.Add(e);
return save;
}
public static void SaveDateBtSerialize()
{
Save save = initDate();
BinaryFormatter bf = new BinaryFormatter();//创造一个二进制对象
FileStream fileStream = File.Create("C:/Users/17641/Desktop" + "/date.txt");
bf.Serialize(fileStream, save);
fileStream.Close();
}
public static Save LoadDateBtSerialize()
{
if (File.Exists("C:/Users/17641/Desktop" + "/date.txt"))
{
//读取文件
BinaryFormatter bf = new BinaryFormatter();
FileStream fileStream = File.Open("C:/Users/17641/Desktop" + "/date.txt", FileMode.Open);
Save save = bf.Deserialize(fileStream) as Save;
fileStream.Close();
return save;
}
else
{
Console.WriteLine("文件不存在");
return null;
}
}
public static void SaveByXML()
{
Save save = initDate();
XmlDocument xmlDocument = new XmlDocument();
#region CreatXML elements
XmlElement root = xmlDocument.CreateElement("Save");
root.SetAttribute("fileName", "file_01");
XmlElement Anode = xmlDocument.CreateElement("Anode");
Anode.InnerText = save.a.ToString();
root.AppendChild(Anode);
XmlElement Bnode = xmlDocument.CreateElement("Bnode");
Bnode.InnerText = save.b;
root.AppendChild(Bnode);
XmlElement Cnode1 = xmlDocument.CreateElement("Cnode1");
Cnode1.InnerText = save.c[0][0];
Cnode1.SetAttribute("Cnode2", save.c[1][2]); //前一个是list列表第二个元素,后一个是字典中int 所对应的2的内容:e.Add(2, "@#$%^&*()");
Cnode1.SetAttribute("Cnode3", "这是同一个Cnode1节点下的数据");
root.AppendChild(Cnode1);
//Cnode1.InnerText = save.c[0][1];使用InnerText如果不创建同名节点,会在同节点下覆盖内容
//root.AppendChild(Cnode1);
Cnode1 = xmlDocument.CreateElement("Cnode1");
Cnode1.InnerText = save.c[0][1];
root.AppendChild(Cnode1);
Cnode1 = xmlDocument.CreateElement("Cnode1");
Cnode1.InnerText = "这是同名Cnode1节点下的数据";
root.AppendChild(Cnode1);
#endregion CreatXML elements
xmlDocument.AppendChild(root);
xmlDocument.Save("C:/Users/17641/Desktop" + "/date.txt");
if (File.Exists("C:/Users/17641/Desktop" + "/date.txt"))
{
Console.WriteLine("XML FILE SAVE");
}
}
public static Save LoadByXML()
{
Save save = new Save();
if (File.Exists("C:/Users/17641/Desktop" + "/date.txt"))
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("C:/Users/17641/Desktop" + "/date.txt");
XmlNodeList aLoad = xmlDocument.GetElementsByTagName("Anode");
//建立一个list集合 装载某个节点下的所有元素
save.a = int.Parse(aLoad[0].InnerText);
XmlNodeList bLoad = xmlDocument.GetElementsByTagName("Bnode");
save.b = bLoad[0].InnerText;
///同名节点读取
XmlNodeList cLoad = xmlDocument.GetElementsByTagName("Cnode1");
d.Add(0, cLoad[0].InnerText);//添加一个字典
d.Add(1, cLoad[1].InnerText);
//save.c.Add(d); 同一个字典添加两次 会在list 里面有两个这个字典(序号不同)
save.c.Add(d);
//save.c.Add(d); 不要将改过的字典再次添加(会再次添加改过后的字典),应该直接通过list的【】调用对应字典的add方法
save.c[0].Add(2, cLoad[2].InnerText);
///同一个节点,读取属性
//XmlAttributeCollection XmlAttributeCollection = cLoad[0].Attributes;
//XmlNode xmlNode = XmlAttributeCollection.GetNamedItem("Cnode1");//读取属性,不能读取未添加的属性,即节点名不等于属性名,例如Cnode1
//e.Add(0, xmlNode.InnerText);
XmlAttributeCollection XmlAttributeCollection1 = cLoad[0].Attributes;
XmlNode xmlNode1 = XmlAttributeCollection1.GetNamedItem("Cnode2");//要根据属性的name值 读取
e.Add(1, xmlNode1.InnerText);
XmlAttributeCollection XmlAttributeCollection2 = cLoad[0].Attributes;
XmlNode xmlNode2 = XmlAttributeCollection2.GetNamedItem("Cnode3");
e.Add(2, xmlNode2.InnerText);
save.c.Add(e);
}
return save;
}
}
}