Unity编辑器扩展:导表工具(2)(通用版)
2019-06-13 18:24
1661 查看
以下均为我个人总结的方案,如果有所不足的地方,请多多包涵
有更好的方案或者有错误之处,敬请留言,谢谢您看了我的博客
二:读取excel数据
首先,需要加入库文件Aspose.Cells 和System.Data库文件
读取excel数据的思路是:将表中所有数据作为文本数据读取,转成DataTable,然后在工具内进行类型转换。
在读取之前,要先定好我们需要的excel表中的格式,基于以后希望能通用到多个项目。所以我定义的格式支持双端,格式如下:
第四行,关键key数量,简单来说,就是索引,是通过多少个关键key找到对应唯一的数据。
例如,目前的大型网络游戏,宠物分成了阶级,在阶级内又分等级,这时候,就是使用2*2,2个关键key来做索引了。
接下来,基于Asopse.Cells,编写一个工具类,用于读取excel表信息。
以后可以基于这个工具类,再进行扩展,做出将数据导出为excel表内容等等功能。
[code]public class AsposeExcelTool { /// <summary> /// 从filetoread读入成DataTable /// </summary> public static DataTable readExcel (string filetoread, string title) { return ReadFromFile(filetoread, title); } private static DataTable ReadFromFile(string filename, string title) { if (!File.Exists(filename)) { Debug.LogWarning("no file"); return null; } if (filename.IndexOf(".xls") < 0) { Debug.LogWarning("no file2"); return null; } try { using (FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { Workbook wb = new Workbook(file); if (wb == null) { Debug.LogWarning("no file3"); return null; } Worksheet ws = null; if (title != null) ws = wb.Worksheets[title]; if (ws == null) { ws = wb.Worksheets[0]; } if (ws == null) { Debug.LogWarning("no file4"); return null; } file.Close(); var iter = ws.Cells.GetEnumerator(); while (iter.MoveNext()) { Cell cell = iter.Current as Cell; if (cell.Value != null) { if (!cell.Value.ToString().Equals(cell.DisplayStringValue)) { Debug.LogError("内容: " + cell.Value.ToString() + " 显示内容: " + cell.DisplayStringValue); Debug.LogError("行:" + (cell.Row + 1) + " 列:" + (cell.Column + 1)); throw new Exception(filename + ":读取出现异常(如果是小数异常,建议重启Unity)"); } } } FixColumns(ws); return FixRows(ws.Cells.ExportDataTableAsString(0, 0, ws.Cells.MaxDataRow + 1, ws.Cells.MaxDataColumn + 1, true)); } } catch (Exception e) { Debug.LogError("Read Error : " + e); } return null; } public static void FixColumns(Worksheet ws) { Cells cs = ws.Cells; List<string> cols = new List<string>(); cols.Clear(); string str; for (int i = 0;i<=cs.MaxDataColumn;i++) { str = ReadCell(cs.GetCell(0, i)); if (!str.Equals("")) { ws.Cells[0, i].PutValue(""); Debug.LogWarning("A DataColumn named " + str + " already belongs to this DataTable in " + ws.Name); } else { cols.Add(str); } } } public static DataTable FixRows(DataTable dt) { while (dt.Rows.Count < 7) { dt.Rows.Add(""); } return dt; } }
现在数据已经都转换成DataTable,接下来就是对数据进行处理。
还记得第一篇章中提到的函数UpdateClientData,这就是我处理数据的函数。
[code] /// <summary> /// 选中文件路径 /// </summary> private string curFilePath; /// <summary> /// 选中文件名字 /// </summary> private string curFileName; /// <summary> /// 选中文件大写名字 /// </summary> private string curNewName; private string fileInfo; //excel里面的中文名字 private int keyNum = 0; //key数量 private bool needError = true; private Dictionary<string, string> dicFileNames; //excel名、excel里面的中文名字 private Dictionary<int, string> dicColumnNames; //excel表内每行对应的中文名字 private Dictionary<int, string> dicClientMembers; //客户端类型对应的属性名 private Dictionary<int, string> dicClientTypes; //客户端类型 private Dictionary<int, string> dicServerMembers; //服务端类型对应的属性名 private Dictionary<int, string> dicServerTypes; //服务端类型 private List<int> index; //列数 private Dictionary<int, Dictionary<int, string>> dicData;//数据字典 private const int EXPORT_TYPE_LUA = 1; private const int EXPORT_TYPE_JSON = 2; private const int EXPORT_TYPE_SCRIPT = 3; private const int EXPORT_TYPE_ASSET = 4; private Dictionary<int, string> EXPORT_TYPE_STRING = new Dictionary<int, string>(); void OnEnable() { EXPORT_TYPE_STRING.Add(EXPORT_TYPE_LUA, ".lua"); EXPORT_TYPE_STRING.Add(EXPORT_TYPE_JSON, ".json"); EXPORT_TYPE_STRING.Add(EXPORT_TYPE_SCRIPT, ".cs"); EXPORT_TYPE_STRING.Add(EXPORT_TYPE_ASSET, ".asset"); } private bool UpdateClientData(FileInfoData fi,int exportType, bool show = true) { //要取回当前的导出文件名 curFilePath = fi.filePath; curFileName = fi.fileName; curNewName = fi.fileNewName; dicColumnNames = new Dictionary<int, string>(); dicClientMembers = new Dictionary<int, string>(); dicClientTypes = new Dictionary<int, string>(); dicData = new Dictionary<int, Dictionary<int, string>>(); dicFileNames = new Dictionary<string, string>(); index = new List<int>(); dicServerMembers = new Dictionary<int, string>(); dicServerTypes = new Dictionary<int, string>(); bool success = ExportExcelToClient(fi, show, exportType); if(show) { if(!success) { Debug.LogError("导出" + curFileName + EXPORT_TYPE_STRING[exportType] + " 失败"); if(show) { EditorUtility.DisplayDialog("导出" + EXPORT_TYPE_STRING[exportType] + "文件", "导出" + curFileName + EXPORT_TYPE_STRING[exportType] + " 失败\n 失败\n 失败\n", "哦,不"); } AssetDatabase.Refresh(); } } return success; }
以上就是一些初始化工作,重点部分在ExportExcelToClient函数里。
[code] private const int CONST_FILE_INFO_ROW_INDEX = 0; //表名index private const int CONST_COLUMN_NAMES_ROW_INDEX = 1; //字段描述index private const int CONST_KEYS_ROW_INDEX = 2; //关键Key index private const int CONST_CLIENT_MEMBERS_ROW_INDEX = 3; //客户端属性名字index private const int CONST_CLIENT_TYPES_ROW_INDEX = 4; //客户端类型index private const int CONST_SERVER_MEMBERS_ROW_INDEX = 5; //服务端属性名字index private const int CONST_SERVER_TYPES_ROW_INDEX = 6; //服务端属性名字index private const string CONST_CLIENT_INT_TYPE = "int"; private const string CONST_CLIENT_STRING_TYPE = "string"; private const string CONST_CLIENT_ARRAY_TYPE = "array"; private static List<string> CLIENT_TYPE_LIST = new List<string>() { CONST_CLIENT_INT_TYPE, CONST_CLIENT_STRING_TYPE, CONST_CLIENT_ARRAY_TYPE, }; private bool ExportExcelToClient(FileInfoData fi, bool show, int exportType) { bool success = true; bool suc; DataTable dataTable = AsposeExcelTool.readExcel(curFilePath, curFileName); if (null == dataTable) { success = false; Debug.LogError(curFilePath + "读取" + curFileName + "表错误,请检查excel的表名字是否与表文件名一直"); return success; } if (dataTable.Rows.Count < (CONST_SERVER_TYPES_ROW_INDEX + 1)) { success = false; Debug.LogError(curFilePath + "配置信息不够" + (CONST_SERVER_TYPES_ROW_INDEX + 1) + " 行"); return success; } try { for (int i = 0; i < dataTable.Rows.Count; i++) { switch (i) { case CONST_FILE_INFO_ROW_INDEX://读取文件内excel名字 fileInfo = dataTable.Rows[CONST_FILE_INFO_ROW_INDEX][dataTable.Columns[0]].ToString(); dicFileNames.Add(curNewName, fileInfo); continue; case CONST_COLUMN_NAMES_ROW_INDEX://读取文件内每行中文名字 success = ReadColumnNames(dataTable); if (!success) return success; continue; case CONST_KEYS_ROW_INDEX://读取key个数 success = ReadKeys(dataTable); if (!success) return success; continue; case CONST_CLIENT_MEMBERS_ROW_INDEX://读取客户端属性名字 success = ReadClientMembers(dataTable, show, out suc); if (!success) return suc; continue; case CONST_CLIENT_TYPES_ROW_INDEX://读取客户端属性类型 success = ReadClientTypes(dataTable, show, out suc); if (!success) return suc; continue; case CONST_SERVER_MEMBERS_ROW_INDEX://读取服务端属性名字 continue; case CONST_SERVER_TYPES_ROW_INDEX://读取服务端属性类型 continue; default: break; } //因为前六行已经在上面进行了判断,并且continue之后,跳过了下面的步骤 if (!show && fi.toJson) return true; Dictionary<int, string> dicRowData = new Dictionary<int, string>(); for (int j = 0; j < dataTable.Columns.Count; j++) { dicRowData[j] = dataTable.Rows[i][dataTable.Columns[j]].ToString(); } dicData[i] = dicRowData;//哪行,对应那一行的所有列数的数据 } //这里接下去是数据导出部分,将在第三篇章放出。 }
以上处理datatable中的数据,之前定义好的excel格式,处理不同行数的数据。
根据不同行数,不同处理如下:
[code] #region 客户端读取各个字段Tool private bool ReadColumnNames(DataTable dataTable) { for (int i=0;i<dataTable.Columns.Count;i++) { dicColumnNames[i] = dataTable.Rows[CONST_COLUMN_NAMES_ROW_INDEX][dataTable.Columns[0]].ToString(); } if (dicColumnNames.Count <=0) { Debug.LogError(curFilePath + "未找到该字段的说明文字,请把表的单元格式设为文字"); return false; } return true; } private bool ReadKeys(DataTable dataTable) { bool success = true; string str = dataTable.Rows[CONST_KEYS_ROW_INDEX][dataTable.Columns[0]].ToString().ToLower(); keyNum = 1; needError = true; if (str.Equals("1*1")) { keyNum = 1; } else if(str.Equals("2*2")) { keyNum = 2; } else if(str.Equals("3*3")) { keyNum = 3; } if (dataTable.Columns.Count > 1) { str = dataTable.Rows[CONST_KEYS_ROW_INDEX][dataTable.Columns[1]].ToString().ToLower(); if (str.Equals("n_error")) { needError = false; } } return success; } private bool ReadClientMembers(DataTable dataTable,bool show,out bool success) { string member; success = true; List<string> memberList = new List<string>(); for (int i= 0;i<dataTable.Columns.Count;i++) { member = dataTable.Rows[CONST_CLIENT_MEMBERS_ROW_INDEX][dataTable.Columns[i]].ToString(); if (string.IsNullOrEmpty(member)||member.Equals("")) { continue;//第几列,空,就跳转,不加入到index中,这样循环的时候,index会找到对应的有数据的列 } if (memberList.Contains(member)) { Debug.LogError(curFilePath + "存在表字段重名: " + member); success = false; return false; } memberList.Add(member); dicClientMembers[i] = member; index.Add(i); } memberList.Clear(); if (dicClientMembers.Count<=0) { if(show) { Debug.LogError(curFilePath + "没有表字段配置,若此表要导出客户端数据,请检查字段设置,并把表的单元格式设置为文字"); success = false; } return false; } return true; 1e92c } private bool ReadClientTypes(DataTable dataTable, bool show, out bool success) { success = true; string type; for (int i=0;i<dataTable.Columns.Count;i++) { type = dataTable.Rows[CONST_CLIENT_TYPES_ROW_INDEX][dataTable.Columns[i]].ToString(); if(!CLIENT_TYPE_LIST.Contains(type)) { if(dicClientMembers.ContainsKey(i)) { Debug.LogError(curFilePath + "第" + (i + 1) + "列配置了错误的客户端数据类型" + type + ",目前仅支持的类型有" + string.Join(",", CLIENT_TYPE_LIST.ToArray())); success = false; return false; } continue; } else { if(!dicClientMembers.ContainsKey(i)) { Debug.LogError(curFilePath + "第" + (i + 1) + "列没有客户端类型名"); success = false; return false; } } dicClientTypes[i] = type; } if (dicClientTypes.Count<=0) { if (show) { Debug.LogError(curFilePath + "没有客户端字段类型配置,若此表要导出客户端数据,请检查字段类型配置,并把表的单元格式设置为“文字”"); success = false; } return false; } return true; } #endregion
经过了这些处理之后,定义的格式中的不同行数的数据就已经全部读取并分类好了。
因我个人小项目只是个单机游戏,所以服务端的部分暂时没有编写。
工具都是慢慢完善的,待以后我完善了也会回头重新梳理写过的文章。
接下来就是将数据运用起来,然后导出我们想要的格式,详细将在第三篇章阐述。
相关文章推荐
- Unity编辑器扩展:导表工具(3)(通用版)
- unity 编辑器工具扩展
- Unity编辑器扩展工具Shader Forge和Behavior Designer(行为树)和 Cinema Director
- unity编辑器扩展 SVN一键更新工具
- Unity编辑器之Hierarchy扩展显示隐藏节点以及图集显示
- Unity 3D - 编辑器扩展之导入文件自动设置Packing Tag
- Unity编辑器扩展记录
- Unity可扩展编辑器
- Unity编辑器扩展
- unity 编辑器扩展 扩展assert编辑器
- Unity扩展编辑器一
- 【Unity编辑器扩展简介】存储数据
- Unity 编辑器扩展教程
- Unity编辑器拓展【菜单扩展】
- Unity编辑器扩展学习笔记(一)——添加菜单选项
- [Unity]Unity3D编辑器插件扩展和组件扩展
- Unity编辑器扩展
- Unity编辑器扩展chapter1
- Unity Editor 编辑器扩展 五 EditorGUI
- unity-编辑器扩展