游戏表格数据序列化自动生成工具

原创 2016年06月01日 13:38:00


大家都知道,数据的持久化保存一般是以二进制形式保存。常用的数据序列化协议有 google的protobuf ,json,Serializab。现在很多游戏开发都是用的是google的protobuf ,之所以用的人那么多,第一是google 提供了针对于各种平台编写的一种自己的解析协议 。服务器端和客户端是用一种解析的协议,那么这样以来网络通信协议定义就比较方便了,包括本地客户端数据持久保存和服务器端表格数据持久保存都可以统一处理。有兴趣的小伙伴可以没事研究一下。我也是在没事的时候,自己也写了一套表格数据自动化生成二进制数据工具。总得来说就是,读取指定目录下的excel表格,将每个表单映射生成一个类,每一个表单每一行就是自动生成一个对象。然后序列化生成二进制bin文件。这种二进制bin文件放在unity工程的UnityAssemblies文件夹下即可。然后再unity中 通过www加载方式加载二进制bin文件,然后进行反序列化即可。这里,我没有进行加密和解密,有兴趣的小伙伴可以自行研究下。我会附带代码。仅作学习参考。用到的主要技术,反射和泛型。

先看效果:

指定目录下的excel表格:



开始编译文件:


反序列读取数据:


在unity中读取结果:


嗯。首先开始写代码。

1.读取excel表格中的表单 根据表单的列定义数据结构。

  1.1配置表格


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Diagnostics;
using System.Threading;


namespace ORMTool
{
    /// <summary>
    /// 在这里面进行配置Excel里面内的表单名字
    /// </summary>
     public class TableConfig
    { 
         public static Dictionary<string, List<string>> arryTable = new Dictionary<string, List<string>>();
         public static List<string> GetArryTable(string excelName)
         {
             List<string> arry;
             arryTable.TryGetValue(excelName, out arry);
             return arry;
         }
         public static void CheckExcelIsConfig()
         {  
             string excelDirectory=Program.excelDirectory;                //***************************改变excel的存放目录
             string[] excelPaths= Directory.GetFiles(excelDirectory);
             arryTable.Clear();
             for (int i = 0; i < excelPaths.Length; i++)
             {
             string excelName = Path.GetFileNameWithoutExtension(excelPaths[i]);
             if(Path.GetExtension(excelPaths[i])==".xls")   //只能打开指定类型的xls文件
              {
              string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + excelPaths[i] + ";" + "Extended Properties=Excel 8.0;"; //2007及以下的excel版本
              //string strConn = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0;HDR=Yes;IMEX=0;'", Path);//2010以上的excel版本
              OleDbConnection conn = new OleDbConnection(strConn);
            try
             {
               conn.Open();
               DataTable daOle=conn.GetSchema("Tables");
               DataTableReader dtReader = new DataTableReader(daOle);
               List<string> tableName = new List<string>();
               while (dtReader.Read())
               {
                   if (dtReader["Table_Name"].ToString().Contains("Config"))
                   {
                       tableName.Add(dtReader["Table_Name"].ToString().Replace('$',' ').Trim());
                   }
               }
               arryTable.Add(excelName, tableName);
               dtReader = null;
               daOle = null;
               conn.Close();
            }
            catch (Exception e)
             {


                Console.WriteLine(e.Message);
             }
                
            } 
          }
        }
    }
}
这段代码 意思是 检查指定目录下的excel文件 是否合法,如果是指定需要编译的表单 将其加入到字典中 等待编译。

1.2创建临时空文件夹 以备将生成的cs文件和 批处理命令放入其中。

        public void GetExcel()
        {
            if (!Directory.Exists("E:\\TempFloder"))
            {
                Console.WriteLine(" no exist");
                Directory.CreateDirectory("E:\\TempFloder");
            }
              CreateApiStringHead();
              CreateBaseClass();//先创建基类
             foreach (var key in TableConfig.arryTable.Keys)
	         {
		          path = @"E:\ExcelTest\" + key + ".xls";
                  ExcelToDS(path,TableConfig.GetArryTable(key));
	         }
                CreateApiStringEnd();
                CreateTableType();//增加枚举
        }
1.3读取excel表单 生成cs文件 xml文件 。一个表单对应一个类,然后将类的成员信息加入到xml文件中 为了能够在用的时候有提示。

 /// <summary>
        /// 连接excel,并编译成实体类
        /// </summary>
        /// <param name="Path">excel路径</param>
        /// <param name="arryTable">此excel下的表单名字数组</param>
        public void ExcelToDS(string Path, List<string> arryTable)
        {
            string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + Path + ";" + "Extended Properties=Excel 8.0;"; //2007及以下的excel版本
            //string strConn = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0;HDR=Yes;IMEX=0;'", Path);//2010以上的excel版本
            OleDbConnection conn = new OleDbConnection(strConn);
            try
            {
                conn.Open();
                string strExcel = "";
                OleDbDataAdapter myCommand = null;
                DataSet ds = null;
                if (arryTable.Count > 0)
                {
                    for (int i = 0; i < arryTable.Count; i++)
                    {
                        strExcel = "select * from [" + arryTable[i] + "$]";
                        myCommand = new OleDbDataAdapter(strExcel, strConn);
                        ds = new DataSet();
                        myCommand.Fill(ds, arryTable[i]);
                        int  attributeCount = ds.Tables[0].Columns.Count;//赋值属性个数
                        CreateEntity(ds.Tables[0], arryTable[i], attributeCount);
                        CreateApiXml(ds.Tables[0], attributeCount, arryTable[i]);
                    }
                }
                conn.Close();

            }
            catch (Exception e)
            {

                Console.WriteLine(e.Message);
            }

        }
        /// <summary>
        /// 创建基类
        /// </summary>
        public void CreateBaseClass()
        {
            StringBuilder cs = new StringBuilder();
            string line = "\r\n";
            //加入命名空间
            cs.Append("using System;").Append(line);
            cs.Append("using System.Collections.Generic;").Append(line).Append(line);
            cs.Append("namespace ").Append(_namespce).Append(line);
            cs.Append("{");
            cs.Append(line).Append(line);
            //加入序列化标识
            cs.Append("[Serializable]").Append(line);
            //加入类名
            cs.Append("  public abstract class ").Append("SerializabBaseObject").Append(line);
            cs.Append("    {");
            cs.Append(line);
            cs.Append("      public int m_id {get;set;}").Append(line);
            cs.Append("      abstract public void Parse(List<SerializabBaseObject> config);").Append(line);
            cs.Append("      abstract public SerializabBaseObject GetRowData(int id);").Append(line);
            cs.Append("      abstract public List<SerializabBaseObject> GetDatas();").Append(line);
            cs.Append("    }");
            cs.Append(line);
            cs.Append("}");
            string pathSave = "E:\\TempFloder\\" + "SerializabBaseObject.cs";    //在此修改生成实体类的路径
            if (System.IO.File.Exists(pathSave))
            {
                System.IO.File.Delete(pathSave);
            }
            System.IO.StreamWriter sw = System.IO.File.CreateText(pathSave);
            sw.Write(cs.ToString());
            sw.Flush();
            sw.Close();
        }
  /// <summary>
  /// 创建实体类
  /// </summary>
  /// <param name="_dataTable">表数据</param>
  /// <param name="className">类名</param>
  /// <param name="attributeCount">属性个数</param>
        public void CreateEntity(DataTable _dataTable, string className, int attributeCount)
        {
            Console.WriteLine("Gening  "+className+"..." );
            StringBuilder cs = new StringBuilder();
            string line = "\r\n";
            //加入命名空间
            cs.Append("using System;").Append(line);
            cs.Append("using System.Collections.Generic;").Append(line).Append(line);
            cs.Append("namespace ").Append(_namespce).Append(line);
            cs.Append("{");
            cs.Append(line).Append(line) ;
            //加入序列化标识
            cs.Append("[Serializable]").Append(line);

            //加入类名
            cs.Append("  public class ").Append(className).Append(":SerializabBaseObject").Append(line);
            cs.Append("    {");
            cs.Append(line);
            //添加私有字段
            for (int i = 0; i < attributeCount; i++)
            {
                ColumnAttribute ca = GetAttributeName(_dataTable.Columns[i].ColumnName);
                cs.Append("     private ").Append(ca.DataType + " ").Append("m_" + ca.AttributeName + "; ");
                cs.Append(line).Append(line);
            }
            //添加属性
            for (int i = 0; i < attributeCount; i++)
            {
                //return m_ID; } set { m_ID = value;
                ColumnAttribute ca = GetAttributeName(_dataTable.Columns[i].ColumnName);
                cs.Append("     /// <summary>").Append(line);
                cs.Append("     ///").Append(ca.Description).Append(line);
                cs.Append("     /// </summary>").Append(line);
                string _str = "{ get { return "+"m_"+ca.AttributeName+"; } set { "+"m_"+ca.AttributeName+" = value; } }";
                cs.Append("     public ").Append(ca.DataType + " ").Append(ca.AttributeName + " ").Append(_str);
                cs.Append(line).Append(line);
            }
            //添加抽象方法
            cs.Append("        private Dictionary<int, SerializabBaseObject> m_datas = null;").Append(line);
            cs.Append("        private List<SerializabBaseObject> m_listDatas = null;").Append(line);

            cs.Append("        public override void Parse(List<SerializabBaseObject> config)").Append(line);
            cs.Append("        {").Append(line);
            cs.Append("            if (m_datas == null)").Append(line);
            cs.Append("                m_datas = new Dictionary<int, SerializabBaseObject>();").Append(line);
            cs.Append("            if(m_listDatas==null)").Append(line);
            cs.Append("                m_listDatas = new List<SerializabBaseObject>();").Append(line);
            cs.Append("                m_datas.Clear();").Append(line);
            cs.Append("                m_listDatas.Clear();").Append(line);
            cs.Append("            for (int i = 0; i < config.Count; i++)").Append(line);
            cs.Append("            {").Append(line);
            cs.Append("                m_datas.Add(config[i].m_id, config[i]);").Append(line);
            cs.Append("            }").Append(line);
            cs.Append("            m_listDatas = config;").Append(line);
            cs.Append("        }").Append(line).Append(line);

            cs.Append("        public override SerializabBaseObject GetRowData(int id)").Append(line);
            cs.Append("        {").Append(line);
            cs.Append("            SerializabBaseObject data = null;").Append(line);
            cs.Append("            if (m_datas.TryGetValue(id, out data))").Append(line);
            cs.Append("            {").Append(line);
            cs.Append("                return data;").Append(line);
            cs.Append("            }").Append(line);
            cs.Append("            return null;").Append(line);
            cs.Append("        }").Append(line).Append(line);

            cs.Append("        public override List<SerializabBaseObject> GetDatas()").Append(line);
            cs.Append("        {").Append(line);
            cs.Append("            if (m_listDatas != null)").Append(line);
            cs.Append("                return m_listDatas;").Append(line);
            cs.Append("            else").Append(line);
            cs.Append("                return null;").Append(line);
            cs.Append("        }").Append(line).Append(line);

            cs.Append("    }");
            cs.Append(line);
            cs.Append("}");
            string pathSave = "E:\\TempFloder\\" + className + ".cs";    //在此修改生成实体类的路径
            if(System.IO.File.Exists(pathSave))
            {
                System.IO.File.Delete(pathSave);
            }
           System.IO.StreamWriter sw=  System.IO.File.CreateText(pathSave);
           sw.Write(cs.ToString());
           sw.Flush();
           sw.Close();
           Console.WriteLine(className + " Gen Success!");
        }
        /// <summary>
        /// 创建xml 头
        /// </summary>
        public void CreateApiStringHead()
        { 
            string line = "\r\n";
            sbApiXml.Append("<?xml version=\"1.0\"?>").Append(line);
            sbApiXml.Append("<doc>").Append(line);
            sbApiXml.Append("    <assembly>").Append(line);
            string spceName = string.Format("        <name>{0}</name>",_namespce);
            sbApiXml.Append(spceName).Append(line);
            sbApiXml.Append("    </assembly>").Append(line);
            sbApiXml.Append("    <members>").Append(line);
        }
        /// <summary>
        /// 创建xml 尾
        /// </summary>
        public void CreateApiStringEnd()
        {
            string line = "\r\n";
            sbApiXml.Append("    </members>").Append(line);
            sbApiXml.Append("</doc>");
            StreamWriter sw = File.CreateText("E:\\TempFloder\\" + dllName+".XML");
            sw.Write(sbApiXml.ToString());
            sw.Flush();
            sw.Close();
        }
        public void CreateApiXml(DataTable _dataTable, int attCount, string className)
        {
            string line = "\r\n";
            for (int i = 0; i < attCount; i++)
            {
                ColumnAttribute ca = GetAttributeName(_dataTable.Columns[i].ColumnName);
                string attName = string.Format("        <member name=\"P:{0}.{1}.{2}\">", _namespce,className, ca.AttributeName);
                sbApiXml.Append(attName).Append(line);
                sbApiXml.Append("            <summary>").Append(line);
                string attDesc = string.Format("              {0}", ca.Description);
                sbApiXml.Append(attDesc).Append(line);
                sbApiXml.Append("            </summary>").Append(line);
                sbApiXml.Append("        </member>").Append(line);

            }
        }
        /// <summary>
        /// 获取列名转化为属性对象
        /// 列名命名规范 列名描述|列名(数据类型) 如 编号|ID(int)
        /// </summary>
        /// <param name="columnName">列名</param>
        /// <returns>属性对象</returns>
        public ColumnAttribute GetAttributeName(string columnName)
        {
            ColumnAttribute ca = new ColumnAttribute();
            ca.Description = columnName.Split('|')[0].ToString();
            ca.AttributeName = columnName.Split('|')[1].Split('(')[0].ToString();
            ca.DataType = columnName.Split('|')[1].Split('(')[1].Split(')')[0].ToString();
            return ca;
        }

        /// <summary>
        /// 创建临时文件夹 存放生成的实体类
        /// </summary>
        public void CreateTempFloder()
        {
            string tempFloderPath = "E:\\TempFloder";
            try
            {

                if (Directory.Exists(tempFloderPath))
                {
                    if (Directory.GetFiles(tempFloderPath).Length != 0)
                    {
                        for (int i = 0; i < Directory.GetFiles(tempFloderPath).Length; i++)
                        {
                            File.Delete(Directory.GetFiles(tempFloderPath)[i]);
                        }
                    }
                    Directory.Delete(tempFloderPath, true);
                }
                Directory.CreateDirectory(tempFloderPath);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
              
            }
        }
 public void CreateTableType()
        {
            string line = "\r\n";
            StringBuilder sb = new StringBuilder();
            sb.Append("using System;").Append(line).Append(line);
            sb.Append("namespace ").Append(_namespce).Append(line);
            sb.Append("{").Append(line).Append(line);
            sb.Append("[Serializable]").Append(line);
            sb.Append("    public enum TableType").Append(line);
            sb.Append("    {").Append(line);
            foreach (var key in TableConfig.arryTable.Keys)
            {
                List<string> tablename= TableConfig.GetArryTable(key);
                for (int i = 0; i < tablename.Count; i++)
                {
                    sb.Append("        " + tablename[i]+",").Append(line);
                }
            }
            sb.Append("    }").Append(line);
            sb.Append("}").Append(line);
            StreamWriter sw = new StreamWriter("E:\\TempFloder\\TableType.cs");
            sw.Write(sb.ToString());
            sw.Flush();
            sw.Close();
        }
    }
    public class ColumnAttribute
    {
       
        public string Description { get; set; } 
        public string AttributeName{get;set;}
        public string DataType { get; set; }


    }


这里面 所有结构类必须继承SerializabBaseObject ,父类规定了一些抽象的方法 必须要实现。因为所有派生类都要继承它,需要解析它。

1.3生成bat批处理命令 并编译cs文件打包成dll。




   /// <summary>
        /// 编译dll
        /// </summary>
        public void GenDll()
        {
            //创建bat 编译命名
            StreamWriter sw = System.IO.File.CreateText(@"E:\TempFloder\gen.bat");
            StringBuilder sb = new StringBuilder();
            sb.Append("@echo off").Append("\r\n");
            //sb.Append(@"cd\").Append("\r\n");
            //sb.Append("C:").Append("\r\n");
            //sb.Append(@"cd WINDOWS\Microsoft.NET\Framework\v3.5").Append("\r\n");
            //string dllNameStr = string.Format(@"csc /target:library /out:e:\TempFloder\{0}.dll e:\TempFloder\*.cs",dllName);
            //sb.Append(dllNameStr).Append("\r\n");
            sb.Append(@"c://WINDOWS/Microsoft.NET/Framework/v3.5/csc /target:library /out:e:\TempFloder\Serializable_0.dll e:\TempFloder\*.cs").Append("\r\n");
            sb.Append("exit");
            sw.Write(sb.ToString());
            sw.Flush();
            sw.Close();
            Process proc = null;
            try
            {
                proc = new Process();
                proc.StartInfo.WorkingDirectory = "E:\\TempFloder";
                proc.StartInfo.FileName = "gen.bat";
                proc.StartInfo.CreateNoWindow = false;
                proc.Start();
                proc.StartInfo.RedirectStandardInput = true;
                proc.WaitForExit();
                while (!isGendllComplte)
                {
                    isGendllComplte = proc.HasExited;
                }
                proc.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
            }
        }
 1.4将生成的dll 拷贝到指定的目录 然后再删除临时文件夹。

 /// <summary>
        /// 将dll剪贴到指定的位置
        /// </summary>
        public void MoveDll()
        {
            if (!isGendllComplte)
            {
                MoveDll();
                return;
            }
            string movePath = "E:\\Libs";
            string dllStr = string.Format("{0}.dll",dllName);
            if (!Directory.Exists(movePath))
            {
                Console.WriteLine("!Error:此目录不存在"+movePath+" ,新建新的目录");
                Directory.CreateDirectory(movePath);
                //return;
            }
            if (File.Exists(movePath + "\\" + dllStr))
            {
                File.Delete(movePath + "\\"+dllStr);
            }
            File.Move("E:\\TempFloder\\"+dllStr, movePath + "\\"+dllStr);
            string[] xmlPaths= Directory.GetFileSystemEntries("E:\\Libs", "*.XML");
            string[] xmlPathsRes = Directory.GetFileSystemEntries("E:\\TempFloder", "*.XML");
            if (xmlPaths.Length != 0)
            {
                for (int i = 0; i < xmlPaths.Length; i++)
                {
                    File.Delete(xmlPaths[i]);
                }
            }
            for (int i = 0; i < xmlPathsRes.Length; i++)
            {
                if (File.Exists(movePath + "\\" + Path.GetFileName(xmlPathsRes[i])))
                {
                    File.Delete(movePath + "\\" + Path.GetFileName(xmlPathsRes[i]));
                }
                File.Move(xmlPathsRes[i],movePath+"\\"+Path.GetFileName(xmlPathsRes[i]));
            }
            if (File.Exists(movePath + "\\" + dllStr))
            {
                string tempFloderPath = "E:\\TempFloder";
                if (Directory.Exists(tempFloderPath))
                {
                    Directory.Delete(tempFloderPath, true);
                }
            }
        }
2.这样表单对应的就有了数据结构,接下来要序列化表单数据。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;

namespace ORMTool
{
    public class SerializableFile
    {
        static private SerializableFile m_inist;
        private readonly string token = "dabe54f00f27e733afcad4bdd91b8675";
        public static SerializableFile Inist { get { if (m_inist == null) return new SerializableFile(); else return m_inist; } }
        public SerializableFile()
        {
            m_inist = this;
        }

        public void Serializable()
        {
            Console.WriteLine("--------开始序列化------");
            foreach (var key in TableConfig.arryTable.Keys)
            {
                string  path = @"E:\ExcelTest\" + key + ".xls";  //暂时只支持2007版一下版本 因为太高版本需要下载组件。麻烦
                 List<string> arryTable=TableConfig.GetArryTable(key);
                 string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + path + ";" + "Extended Properties=Excel 8.0;"; //2007及以下的excel版本
                 //string strConn = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0;HDR=NO;IMEX=1'", path);//2010以上的excel版本
                OleDbConnection conn = new OleDbConnection(strConn);
                try
                {
                    conn.Open();
                  
                    string strExcel = "";
                    OleDbDataAdapter myCommand = null;
                    DataSet ds = null;
                    if (arryTable.Count > 0)
                    {
                        for (int i = 0; i < arryTable.Count; i++)
                        {
                            strExcel = "select * from [" + arryTable[i] + "$]";
                            myCommand = new OleDbDataAdapter(strExcel, strConn);
                            ds = new DataSet();
                            myCommand.Fill(ds, arryTable[i]);
                            FillDate(ds.Tables[0],arryTable[i]);
                        }
                    }
                    conn.Close();
                   
                }
                catch (Exception e)
                {

                    Console.WriteLine(e.Message);
                    return;
                }
            }
            Console.WriteLine("--------序列化完毕------"); 
        }
        private void FillDate(DataTable dt,string genFileName)
        {
            Console.WriteLine("------Serializeing "+genFileName);
            List<object> serObjs = new List<object>();
            string dllPath = "E:\\Libs\\Serializable_0.dll";
            Assembly ass = Assembly.LoadFile(dllPath);
            Type objectType = ass.GetType(Program._namespce+"." + genFileName); //********
            Program pro=new Program();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                    object obj = Activator.CreateInstance(objectType);// 创建实例
                    PropertyInfo[] infos = obj.GetType().GetProperties();
                    for (int n = 0; n < dt.Columns.Count; n++)
                    {
                        ColumnAttribute ca = pro.GetAttributeName(dt.Columns[n].ColumnName);
                        if (n == 0) //第一行id列
                        {
                            PropertyInfo[] memberInfos = obj.GetType().GetProperties();
                            foreach (PropertyInfo item in memberInfos)
	                          {
                                     if(item.Name=="m_id")
                                     {
                                         item.SetValue(obj, int.Parse(dt.Rows[i][0].ToString()));
                                     }
	                          }
                        }
                        foreach (PropertyInfo info in infos)
                        {
                            if (info.Name == ca.AttributeName && info.CanWrite)
                            {
                                if (dt.Rows[i][n] == null || string.IsNullOrEmpty(dt.Rows[i][n].ToString()))
                                {
                                    break;
                                }
                                if (IsType(info.PropertyType, "System.String"))   //在此添加所支持的数据类型
                                { 
                                    ReflectionSetProperty(obj, ca.AttributeName, dt.Rows[i][n].ToString());
                                    break;
                                }
                                else if (IsType(info.PropertyType, "System.Boolean"))
                                {
                                    ReflectionSetProperty(obj, ca.AttributeName, (Boolean.Parse(dt.Rows[i][n].ToString())));
                                    break;
                                }
                                else if (IsType(info.PropertyType, "System.Int32"))
                                {
                                    ReflectionSetProperty(obj, ca.AttributeName, int.Parse(dt.Rows[i][n].ToString()));
                                    break;
                                }
                                else if (IsType(info.PropertyType, "System.Int64"))
                                {
                                    ReflectionSetProperty(obj, ca.AttributeName, (Int64.Parse(dt.Rows[i][n].ToString())));
                                    break;
                                }
                                else if (IsType(info.PropertyType, "System.Single"))
                                {
                                    ReflectionSetProperty(obj, ca.AttributeName, float.Parse(dt.Rows[i][n].ToString()));
                                    break;

                                }
                            }
                        }
                    }
                    serObjs.Add(obj);
                
            }    //序列化
                BinaryFormatter bf = new BinaryFormatter();
                FileStream sw = File.Create("E:\\Libs\\" + genFileName+".bin");  //*************c此处修改生成的二进制扩展名
                bf.Serialize(sw, serObjs);
                sw.Close();
                Console.WriteLine("------Serialize Complte " + genFileName);
        }
        /// <summary>
        /// 给属性赋值
        /// </summary>
        /// <param name="objClass"></param>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        private void ReflectionSetProperty(object objClass, string propertyName,object value)
        { 
            PropertyInfo[] infos=objClass.GetType().GetProperties();
            foreach (PropertyInfo info in infos)
	        {
		        if(info.Name==propertyName&&info.CanWrite)
                {
                    info.SetValue(objClass, value, null);
                    break;
                }
	        }
        }
        /// <summary>
        /// 反序列化 返回值为object 需要在泛型类中进行类型转化
        /// </summary>
        /// <param name="binPath">需要反序列化的二进制文件路径</param>
        /// <returns></returns>
        public object DeSerialize(string binPath)
        {
            if (!File.Exists(binPath))
            {
                Console.WriteLine("!warring: Not Found "+binPath);
                return null;
            }
            FileStream fs = File.Open(binPath, FileMode.Open);
            //序列化
            BinaryFormatter bf = new BinaryFormatter();
            object oj= bf.Deserialize(fs);
            fs.Close();
            return oj;
        }
        /// <summary>
        /// 类型匹配
        /// </summary>
        /// <param name="type"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public  bool IsType(Type type, string typeName)
        {
            if (type.ToString() == typeName)
                return true;
            if (type.ToString() == "System.Object")
                return false;

            return IsType(type.BaseType, typeName);
        }
    }
}
这里面用的是反射技术。不懂得小伙伴可以百度查资料。
这样生成完成后 就有了一个二进制bin文件。有了dll类库,那么就可以去读取数据利用反射可以创建对象。
3.定义泛型对象。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;


namespace ORMTool
{
    /// <summary>
    /// 泛型类
    /// author:wangyunfei
    /// email:1172906928@qq.com
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ProtoData<T> : IEnumerable where T : ORMTool.SerializabBaseObject
    {
        public T[] items;


        public ProtoData(byte[] bytes)
        {
            MemoryStream ms = new MemoryStream(bytes);
            BinaryFormatter bt = new BinaryFormatter();
            object ob= bt.Deserialize(ms);
            if (ob == null) return;
            List<object> list = ob as List<object>;
            if (list == null) return;
            items = new T[list.Count];
            for (int i = 0; i < list.Count; i++)
            {
                T t = list[i] as T;
                if (t != null)
                {
                    items[i] = t;
                }
            }
        }
        public ProtoData(object ob)
       {   
           if (ob == null) return;
           List<object> list = ob as List<object>;
           if (list == null) return;
           items = new T[list.Count];
           for (int i = 0; i < list.Count; i++)
           {
               T t=  list[i] as T;
               if (t != null)
               {
                   items[i] = t;
               }  
           }
       }
        // Implementation for the GetEnumerator method.
        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)GetEnumerator();
        }
        /// <summary>
        /// 参考 https://msdn.microsoft.com/zh-cn/library/system.collections.ienumerable.getenumerator.aspx
        /// </summary>
        /// <returns></returns>
        public Node GetEnumerator()
        {
            return new Node(items);
        }
        /// <summary>
        /// 节点类
        /// </summary>
        public  class Node:IEnumerator
        {
         public T[] _node;
        int position = -1;
        public Node(T[] list)
       {
           _node = list;
        }


       public bool MoveNext()
       {
        position++;
        return (position < _node.Length);
       }


       public void Reset()
       {
        position = -1;
       }


       object IEnumerator.Current
       {
        get
        {
            return Current;
         }
       }
       public T Current
       {
        get
        {
            try
            {
                return _node[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
         }
       }
     }
   }
}
这个代码的意思是 每个类都是派生出来的,都继承了SerializabBaseObject,在序列化时,我们知道派生类型,但是反序列出来后并不知道其类型。只是一个object类型,那么做个泛型类就很方便的根据读取的bin数据转化对应的数据类型。防止类型转化出现错误。

4.解析每个bin数据。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace ORMTool
{
    public  class TableManager
    {
        private static TableManager m_Instance=null;
        public static TableManager Instance { get { if (m_Instance == null) return new TableManager(); else return m_Instance; } }
        private Dictionary<TableType, SerializabBaseObject> tables = null;
        public TableManager()
        {
            m_Instance = this;
            if (tables == null)
            {
                tables = new Dictionary<TableType, SerializabBaseObject>();
            }
            tables.Clear();
            _Parse();
            //Parse();
        }
        /// <summary>
        /// 此方法暂时有问题 
        /// </summary>
        private void Parse()
        {
            string dllPath = "E:\\Libs\\Serializable_0.dll";
            Assembly ass = Assembly.LoadFile(dllPath);
            string[] enumNames= Enum.GetNames(typeof(TableType));
            for (int i = 0; i < enumNames.Length; i++)
            {
                if (!string.IsNullOrEmpty(enumNames[i]))
                {
                    object oj = SerializableFile.Inist.DeSerialize(string.Format("E:\\Libs\\{0}.bin",enumNames[i]));
                    ProtoData<SerializabBaseObject> s = new ProtoData<SerializabBaseObject>(oj);
                    List<SerializabBaseObject> items = s.items.ToList<SerializabBaseObject>();
                    Type objectType = ass.GetType(Program._namespce + "." + enumNames[i]);
                    //Type generic = typeof(List<SerializabBaseObject>);
                    //Type constructed = generic.MakeGenericType(new Type[] { typeof(SerializabBaseObject) });
                    object obj = Activator.CreateInstance(objectType);// 创建实例
                    MethodInfo methodInfo = obj.GetType().GetMethod("Parse");
                    methodInfo.Invoke(obj, new object[]{items});
                    SerializabBaseObject obActor = (SerializabBaseObject)obj;
                    tables.Add(GetEnume(enumNames[i]), obActor);
                    Console.WriteLine("Parse "+enumNames[i]+" Complte------");
                }
            }
          

        }
        private void _Parse()
        {
            string[] enumNames = Enum.GetNames(typeof(TableType));
            for (int i = 0; i < enumNames.Length; i++)
            {
                if (!string.IsNullOrEmpty(enumNames[i]))
                {
                    object oj = SerializableFile.Inist.DeSerialize(string.Format("E:\\Libs\\{0}.bin", enumNames[i]));
                    ProtoData<SerializabBaseObject> s = new ProtoData<SerializabBaseObject>(oj);
                    List<SerializabBaseObject> items = s.items.ToList<SerializabBaseObject>();
                    SerializabBaseObject config=null;
                    switch (enumNames[i])
                    {
                        case "MessageTextConfig":
                            config = new MessageTextConfig();
                            break;
                        default:
                            break;
                    }
                    config.Parse(items);
                    tables.Add(GetEnume(enumNames[i]), config);
                    Console.WriteLine("Parse " + enumNames[i] + " Complte------");
                }
            }
        }
        /// <summary>
        /// 注册类型
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        TableType GetEnume(string name)
        {
            switch (name)
            {
                case "MessageTextConfig":
                    return TableType.MessageTextConfig;
            }
            return TableType.MessageTextConfig;
        }
        public SerializabBaseObject GetTableRowData(TableType type, int tableid)
        {
            SerializabBaseObject data = null;
            if (tables.TryGetValue(type, out data))
            {
                data= data.GetRowData(tableid);
            }
            return data;
        }
        public List<SerializabBaseObject> GetTableDatas(TableType type)
        {
            SerializabBaseObject data = null;
            if (tables.TryGetValue(type, out data))
            {
              return data.GetDatas();
            }
            return null;
        }

    }
}
每个bin对应一个表单对象集合,需要从其中反射出来对应的对象,然后缓存到集合中以供使用。所以,每个派生类都实现了parse方法,就是解析bin数据映射到对应对象上。
5. unity中读取bin数据。

将生成的dll和xml放在Library\UnityAssemblies下面 这样的话属性就会有提示信息。也可以将dll直接放assets下面 xml 不用了 这样只是没有提示信息而已。

 void OnGUI()
    {
        if (GUILayout.Button("load"))
        {
            StartCoroutine(Load((bytes) => {
                ProtoData<ORMTool.MessageTextConfig> _config = new ProtoData<ORMTool.MessageTextConfig>(bytes);
                foreach (ORMTool.MessageTextConfig item in _config)
                {
                    Debug.Log(item.ID+"-"+item.ChineseText+"-"+item.KokrText);
                }
            }));
        }
    }
    IEnumerator Load(CallBack callback)
    {
        string url = "file:///"+Application.streamingAssetsPath + "/MessageTextConfig.bin";
        WWW www = new WWW(url);
        yield return www;
        if (string.IsNullOrEmpty(www.error))
        {
            if (callback != null)
                callback(www.bytes);
        }
        else
        {
            Debug.LogError(www.error);
        }
    }
至此,全部完毕。如有不清楚的可以联系我QQ 1172906928. 个人原创,不喜勿喷,仅供相互学习,不足之处多多指点。

源码链接:http://pan.baidu.com/s/1c1BCvc8(提取码:3wan)


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

《Unity 3D游戏客户端基础框架》protobuf 导excel表格数据

之前使用NPOI插件编写的导表工具,其实就是直接将数据进行序列化,解析时还需要进行反序列化,步骤比较繁复,最近看到Google的一个开源的项目protobuf,不仅可以用于进行excel表格数据的导出...

(NO.00005)iOS实现炸弹人游戏(七):游戏数据的序列化表示

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 用plist列表文件来表示游戏数据因为在这个炸弹人游戏中有...
  • mydo
  • mydo
  • 2015年12月24日 15:39
  • 1484

数据序列化学习

  • 2012年10月19日 17:15
  • 413KB
  • 下载

android下xml序列化工具,生成xml文件方法

ss

Avro数据序列化系统(1)

  • 2015年12月25日 13:35
  • 25.78MB
  • 下载

android Service 和 数据序列化

  • 2016年09月28日 21:36
  • 10.21MB
  • 下载

自动对象序列化和网络数据解析,数据模型和字典的互转

常用场景: 将网络请求Json数据、NSDictionary、数组,映射为数据模型。 将数据模型对象序列化成字典保存 特性: 实现对象正向反向映射, 自动判断属性类型,使用...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:游戏表格数据序列化自动生成工具
举报原因:
原因补充:

(最多只允许输入30个字)