unity的XML读取

在unity游戏开发中很多时候都需要策划配置一些XML表,但是XML的读取效率并不高,相比XML读取txt的效率会高一些,这样我们可以用C#的序列化与反序列化来做这样的转化。

先在editor下将XML表读取到内存,然后序列化到txt中,然后游戏中只用读取txt然后反序列化就得到数据了。


XML格式如下:

<root>
<sample sid="1" class="www.projectName.fileName" name="名字1"/>
<sample sid="2" class="www.projectName.fileName" name="名字2"/>
</root>


要存储表里记录要用[Serializable]修饰对象,我定义了一个基类BaseTemplate

using UnityEngine;
using System.Collections;
using System;


[Serializable]
abstract public class BaseTemplate
{
	public int sid;//配置编号(不可重复)
	public string name;//名称


	public static System.Type getTypeFromClass(string className)
	{
		if(className == "www.projectName.fileName")
		{
			return typeof(TestTemplate);
		}
		return null;
	}
	
	public static BaseTemplate create(System.Type t)
	{
		object o = System.Activator.CreateInstance(t);
		return (BaseTemplate)o;
	}
	
	public abstract void postProcess();
}
getTypeFromClass方法用于获取配置表中class字段与自己定义的class对应


所有配置类都继承它,如:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

[Serializable]
public class TestTemplate : BaseTemplate
{
	public static Dictionary<int, BaseTemplate> manager = new Dictionary<int, BaseTemplate>();

	public override void postProcess()
	{

	}
}


Serializable:要使一个类可序列化,最简单的方法是使用 Serializable 属性对它进行标记。

Deserialize:反序列化,需要知道文件存储的类型,然后强制转换就好了。


我的XML文件放都在Assets/ZBuffer/XML下,序列化的二进制文件存储在Resources/Data下面(文件名同类名)。

序列化与反序列化的代码如下:

using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary; 
using UnityEditor;
using UnityEngine;

public class XMLBuile
{
	static List<System.Type> templateTypeList = new List<System.Type>();
	static void init()
	{
		templateTypeList.Clear ();
		templateTypeList.Add (typeof(TestTemplate));
	}

	//for building xml files
	[MenuItem("Tool/Build/Build XML")]
	static void buildXML()//序列化
	{
		init ();
		string dir = Application.dataPath + "/ZBuffer/XML/";
		DirectoryInfo dirinfo = new DirectoryInfo(dir);
		FileInfo[] infos = dirinfo.GetFiles();
		for(int i = 0; i < infos.Length; ++i)
		{
			string filename = infos[i].FullName;
			if(Path.GetExtension(filename) == ".xml")
			{
				ReadXML (filename);
			}
		}
		saveAllTemplateToSerialFile ();
	}
	static void saveAllTemplateToSerialFile()
	{
		for(int i = 0; i < templateTypeList.Count; ++i)
		{
			FileSerialize (templateTypeList[i]);
		}
	}
	static void ReadXML(string filename)
	{
		Debug.Log (filename);
		byte[] bytes = null;
		bytes = File.ReadAllBytes (filename);
		realLoad(bytes);
	}
	static void realLoad(byte[] bytes)
	{
		if (bytes != null) 
		{
			XmlDocument xmlDoc = new XmlDocument();
			xmlDoc.Load (new MemoryStream (bytes));
			XmlNode rootNode = xmlDoc.FirstChild;
			if (rootNode.Name == "root")
			{				
				string className = "";
				int rscCount = rootNode.ChildNodes.Count;
				if(rscCount > 0)
				{
					for (int n = 0; n < rscCount; n++) 
					{
						XmlNode node = rootNode.ChildNodes[n];
						if(node.Name == "sample")
						{
							for (int m = 0; m < node.Attributes.Count; m++) 
							{
								XmlAttribute attr = node.Attributes[m];
								if(attr.Name == "class")
								{
									className = attr.Value;
									break;
								}
							}
						}
						if(className != "")
						{
							break;
						}
					}
				}
				if(className == "")
				{
					Debug.Log("<color=red>load failure xml file format error</color>");
				}
					
				for (int n = 0; n < rscCount; n++) 
				{
					XmlNode node = rootNode.ChildNodes[n];
					if(node.Name == "sample")
					{
						for (int m = 0; m < node.Attributes.Count; m++) 
						{
							XmlAttribute attr = node.Attributes[m];
							if(attr.Name == "class")
							{
								className = attr.Value;
								break;
							}
						}
					}
					System.Type type = BaseTemplate.getTypeFromClass(className);
					if(type == null)
					{
						continue;
					}
					FieldInfo fi = type.GetField("manager");
					Dictionary<int, BaseTemplate> manager = (Dictionary<int, BaseTemplate>)(fi.GetValue(null));
					
					if(node.Name == "sample")
					{
						if(node.Attributes == null)
						{
							continue;
						}
						BaseTemplate tmpl = BaseTemplate.create(type);
						for (int m = 0; m < node.Attributes.Count; m++) 
						{
							XmlAttribute attr = node.Attributes[m];
							if(attr.Name == "class")
							{
								continue;
							}
							loadAttribute(attr, type, tmpl);
						}
						manager[tmpl.sid] = tmpl;
						tmpl.postProcess();
					}
				}
			}
		}
		else
		{
			Debug.Log("<color=red>load failure </color>");
		}			
	}
	
	static void loadAttribute(XmlAttribute attr, System.Type type, BaseTemplate tmpl)
	{
		string attrName = attr.Name;
		FieldInfo fi = type.GetField(attrName);
		if(fi == null)
		{   
			Debug.Log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ failure : " + attrName); 
		}
		else
		{
			if(fi.FieldType == typeof(int))
			{
				fi.SetValue(tmpl, int.Parse(attr.Value));
			}
			else if(fi.FieldType == typeof(string))
			{
				fi.SetValue(tmpl, attr.Value);
			}
			else if(fi.FieldType == typeof(float))
			{
				fi.SetValue(tmpl, float.Parse(attr.Value));
			}
			
		}
	}

	public static bool FileSerialize (System.Type type)
	{
		BinaryFormatter bf = new BinaryFormatter();
		FileStream file = File.Create(getSerialFilePathInDataFolder(type));
		FieldInfo fi = type.GetField("manager");
		
		Dictionary<int, BaseTemplate> manager = (Dictionary<int, BaseTemplate>)(fi.GetValue(null));
		if(manager == null)
		{
			return true;
		}
		bf.Serialize(file, manager);
		file.Close();
		return true;
	}

	static string getSerialFilePathInDataFolder(System.Type type)
	{
		string filename = type.ToString ();
		return Application.dataPath + "/Resources/Data/" + filename + ".txt";
	}

	//反序列化
	static public void loadAll()
	{
		init ();
		loadAllTemplateFromSerialFile();
	}
	static bool loadAllTemplateFromSerialFile()
	{
		bool suc = true;
		for(int i = 0; i < templateTypeList.Count; ++i)
		{
			bool b = load (templateTypeList[i]);
			suc &= b;
		}
		return suc;
	}
	
	static bool load(System.Type type)
	{
		BinaryFormatter bf = new BinaryFormatter();
		
		FieldInfo fi = type.GetField("manager");
		Dictionary<int, BaseTemplate> manager = (Dictionary<int, BaseTemplate>)(fi.GetValue(null));
		if(manager == null)
		{
			return true;
		}
		
		FileStream file = File.Open(getSerialFilePathInUserFolder(type), FileMode.Open);
		manager = (Dictionary<int, BaseTemplate>)bf.Deserialize(file);
		fi.SetValue(null, manager);
		file.Close ();	
		
		return true;
	}
	static string getSerialFilePathInUserFolder(System.Type type)
	{
		string filename = type.ToString ();
		return Application.persistentDataPath + "/data/" + filename + ".txt";
	}
}

序列化在Editor下执行,反序列化只需调用XMLBuile.loadAll(); 就行了。


项目中看到的效果是,之前读取所有XML需要十几秒,现在2秒左右。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nmg10

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值