需要用到的dll插件
Excel格式:
第一行为标题
第二行设置是否是索引列,索引列的内容会被转成列表形式
第三行设置数据类型
后面添加数据具体内容
如果第一列内容为空,不读取本行内容,可以用来处理备注
(如果第一行标题为空,不读取这一列数据,默认为备注行,这个需求暂未添加)
一 、添加Excel 转json工具
using Excel;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using UnityEngine;
using UnityEditor;
public class MasterToJson
{
/// <summary>
/// 配置文件存放在项目根目录
/// </summary>
static string fileDirPath = @"ConfigExcel";
private static string outPath = "OutPutJson";
private static string KeyText = "k";
[MenuItem("Tool/Master To Json Text")]
static void ChangeToJson()
{
string excelFolderPath = Path.Combine(Application.dataPath, fileDirPath);
DirectoryInfo dir = new DirectoryInfo(excelFolderPath);
FileInfo[] fileInfos = dir.GetFiles("*", SearchOption.AllDirectories);
for (int i = 0; i < fileInfos.Length; i++)
{
ExportFile(fileInfos[i].FullName);
}
}
/// <summary>
/// 导出单个excel内容
/// </summary>
/// <param name="filePath"></param>
static void ExportFile(string filePath)
{
if (filePath.EndsWith("meta") || filePath.Contains("$")) return;
//取Excel名字的第一部分作为保存文件名称
Debug.Log(filePath);
string excelName = Path.GetFileNameWithoutExtension(filePath);
using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
IExcelDataReader excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
DataSet result = excelDataReader.AsDataSet();
DataTableCollection tables = result.Tables;
foreach (DataTable sheetTable in tables)
{
//Debug.Log("table sheet Name is " + sheetTable.TableName);
//获取需要转换的sheet标签页,sheet页名称不包含#并且不以下划线开头,#是备注类用的表,下划线是服务器用的表
if (sheetTable.TableName.IndexOf('#') == -1 && (sheetTable.TableName.IndexOf('_') > 0 || sheetTable.TableName.IndexOf('_') == -1))
{
ConvertSheetToJson(sheetTable, excelName);
}
}
excelDataReader.Dispose();
};
}
/// <summary>
/// 把单个sheet文件转json
/// </summary>
/// <param name="data"></param>
/// <param name="excelName"></param>
static void ConvertSheetToJson(DataTable sheetTable, string excelName)
{
int columIndex = 0;
int keyCount = 0;
int columnsCount = sheetTable.Columns.Count;
int rowCount = sheetTable.Rows.Count;
if (columnsCount <= 3 || rowCount <= 1) {
Debug.Log("skip empty table:" + sheetTable.TableName);
return;
}
//List<string> titleList = new List<string>();
List<ColumData> paramsList = new List<ColumData>();
for (int i = 0; i < columnsCount; i++)
{
ColumData cData = new ColumData();
string content = sheetTable.Rows[2][i].ToString();
if (IsString(content)) cData.type = ParamsType.String;
else if(IsInt(content)) cData.type = ParamsType.Int;
else cData.type = ParamsType.None;
paramsList.Add(cData);
}
JSONObject tableJson = new JSONObject();
JSONObject contentJson = new JSONObject();
tableJson.AddField(sheetTable.TableName, contentJson);
bool isFinish = false;
for (int i = 0; i < rowCount; i++)
{
JSONObject job = new JSONObject();
for (int j = 0; j < columnsCount; j++)
{
if (i == 0)//标题
{
paramsList[j].name = sheetTable.Rows[i][j].ToString();
}else if (paramsList[j].type != ParamsType.None)
{
if (i == 1)//索引类型 keyText 表示该列是索引
{
if (sheetTable.Rows[i][j].ToString().Equals(KeyText))
{
keyCount++;
paramsList[j].isKey = true;
}
}
else if (i == 2) continue;
else
{
if (j == 0 && string.IsNullOrEmpty(sheetTable.Rows[i][j].ToString())) //第一列内容为空,判定该表内容读取结束
{
continue;
}
if (!paramsList[j].isKey)
{
GetColumJson(sheetTable.Rows, 0, i, paramsList, job);
string res = job.ToString();
Debug.Log(res);
break;
}
}
}
}
if (job && !job.IsNull)
{
contentJson.Add(job);
}
}
SaveFile(tableJson.ToString(), excelName, sheetTable.TableName);
}
/// <summary>
/// 把表格单行数据转换为json对象
/// </summary>
/// <param name="item"></param>
/// <param name="columnIndex"></param>
/// <param name="rowIndex"></param>
/// <param name="paramsList"></param>
/// <param name="job"></param>
private static void GetColumJson(DataRowCollection item, int columnIndex, int rowIndex, List<ColumData> paramsList, JSONObject job)
{
if (columnIndex >= paramsList.Count) return;
if (paramsList[columnIndex].type == ParamsType.None)
{
columnIndex++;
GetColumJson(item, columnIndex, rowIndex, paramsList, job);
}
else if (paramsList[columnIndex].isKey && columnIndex > 0)
{
string arrKey = "index_list";
JSONObject jsonArr = new JSONObject();
JSONObject itemJson = new JSONObject();
jsonArr.Add(itemJson);
job.AddField(arrKey, jsonArr);
itemJson.AddField(paramsList[columnIndex].name, item[rowIndex][columnIndex].ToString());
columnIndex++;
GetColumJson(item, columnIndex, rowIndex, paramsList, itemJson);
}
else {
job.AddField(paramsList[columnIndex].name, item[rowIndex][columnIndex].ToString());
columnIndex++;
GetColumJson(item, columnIndex, rowIndex, paramsList, job);
}
}
private static bool IsInt(string typeName)
{
if (typeName.ToLower().Contains("int") || typeName.ToLower().Contains("timestamp"))
{
return true;
}
return false;
}
private static bool IsString(string typeName)
{
if (typeName.ToLower().Contains("string") || typeName.ToLower().Contains("time") || typeName.ToLower().Contains("text"))
{
return true;
}
return false;
}
private static void SaveFile(string content, string excelName, string sheetName)
{
string groupName = excelName.Split('_')[0];
string saveFolderPath = Path.Combine(outPath, groupName);
saveFolderPath = Path.Combine(Application.dataPath, saveFolderPath);
if (!Directory.Exists(saveFolderPath))
Directory.CreateDirectory(saveFolderPath);
File.WriteAllText(Path.Combine(saveFolderPath, sheetName + ".json"), content);
}
protected enum ParamsType
{
None,
Int,
String,
}
protected class ColumData
{
public string name;
public ParamsType type;
public bool isKey;
}
}
二、添加Excel 转C#数据类工具
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Linq;
using Excel;
using System.Data;
public class MasterToCs
{
static List<string> masterNameList = new List<string>()
{
"unit_config.xlsx",
};
[MenuItem("Tool/Master To Client Template")]
public static void MasterExport()
{
foreach (var item in masterNameList)
{
MasterUtil.Export(item);
}
}
class MasterUtil
{
private const string TemplatePath = "/Editor/MasterToCS/Template/";
private const string TemplateOneKeyFile = "template_1key.txt";
private const string TemplateTwoKeyFile = "template_2key.txt";
private const string TemplateThreeKeyFile = "template_3key.txt";
private const string TemplateFourKeyFile = "template_4key.txt";
private const string TemplateParamFile = "template_param.txt";
// 直接更新所有的表文件,使用这个路径
private const string OutputPath = "output";
private const string TemplateFile = "";
private const string KeyText = "k";
private const string MasterUpperNameReplaceStr = "[MasterName]";
private const string MasterLowerNameReplaceStr = "[mastername]";
private const string ParamListStr = "[paramList]";
private const string MasterFilePath = @"ConfigExcel/";
public static string masterGroupName = "";
public static string outputFilePath = "";
static string appPath = Application.dataPath;
public static void Export(string masterFileName)
{
masterGroupName = "";
string[] tmpGroupName = masterFileName.Split('.')[0].Split('_');
for (int i = 0; i < tmpGroupName.Count() - 1; i++)
{
masterGroupName += GetUpperName(tmpGroupName[i]);
}
outputFilePath = OutputPath + "/" + masterGroupName;
outputFilePath = Path.Combine(Application.dataPath, outputFilePath);
//Debug.Log("输出文件名 : " + masterGroupName);
Debug.Log("输出路径 : " + outputFilePath);
if (!Directory.Exists(outputFilePath))
{
Debug.Log("创建路径" + outputFilePath);
Directory.CreateDirectory(outputFilePath);
}
#region excel
string masterFilePath = MasterFilePath + masterFileName;
masterFilePath = Path.Combine(Application.dataPath, masterFilePath);
if (!File.Exists(masterFilePath))
{
Debug.LogError("not exist path.." + masterFilePath);
return;
}
using (FileStream stream = File.Open(masterFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
IExcelDataReader excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
DataSet result = excelDataReader.AsDataSet();
DataTableCollection tables = result.Tables;
foreach (DataTable item in tables)
{
Debug.Log("tableName is "+item.TableName);
ConvertSheetToCs(item);
}
excelDataReader.Dispose();
};
Debug.Log("export template finish!");
#endregion
}
/// <summary>
/// 转换单个sheet表,生成对应的数据类
/// </summary>
/// <param name="sheet"></param>
static void ConvertSheetToCs(DataTable sheet)
{
//列数
int colNum = 0;
//主键个数
int keyCnt = 0;
List<ColumData> columList = new List<ColumData>();
while (true)
{
if (colNum >= sheet.Columns.Count) break;
string columName = sheet.Rows[0][colNum].ToString();
string columType = sheet.Rows[2][colNum].ToString();
if (columName == "")
{
break;
}
if (columType != "")
{
Debug.LogError(sheet.Rows[1][colNum].ToString().ToLower() + "-->" + colNum);
bool isKey = sheet.Rows[1][colNum].ToString().ToLower().Equals( KeyText ) ? true : false;
if (isKey)
{
keyCnt++;
}
//Debug.Log(columName + " (" + columType + "), isKey : " + isKey);
ColumData data = new ColumData(columName, columType, isKey);
columList.Add(data);
}
colNum++;
}
Debug.Log("keyCnt : " + keyCnt);
if (keyCnt == 1)
{
ConvertOneKeyMaster(sheet, columList);
}
if (keyCnt < 5 && keyCnt > 1)
{
ConvertTwoMoreKeyMaster(sheet, columList, keyCnt);
}
if (keyCnt >= 5)
{
Debug.LogError("========= 暂不支持5个以上主键,请添加template文件。");
}
}
/// <summary>
/// 包含单个主键的配置表
/// </summary>
/// <param name="sheet"></param>
/// <param name="columList"></param>
private static void ConvertOneKeyMaster(DataTable sheet, List<ColumData> columList)
{
string masterNameInLower = sheet.TableName;
string masterNameInUpper = GetUpperName(masterNameInLower);
Debug.Log("master class 名 : " + masterNameInLower + " / " + masterNameInUpper);
string appPath = Application.dataPath;
string template_file_path = appPath + TemplatePath + TemplateOneKeyFile;
Debug.Log("template file path : " + template_file_path);
if (!System.IO.File.Exists(template_file_path))
{
Debug.LogWarning("not find template!");
return;
}
string template_file_data = string.Empty;
using (System.IO.StreamReader sr = new System.IO.StreamReader(template_file_path))
{
template_file_data = sr.ReadToEnd();
}
template_file_data = template_file_data.Replace(MasterUpperNameReplaceStr, masterNameInUpper);
template_file_data = template_file_data.Replace(MasterLowerNameReplaceStr, masterNameInLower);
string template_param_file_path = appPath + TemplatePath + TemplateParamFile;
string param_template = "";
string param_str = "";
using (System.IO.StreamReader sr = new System.IO.StreamReader(template_param_file_path))
{
param_template = sr.ReadToEnd();
}
var keyList = columList.Where(t => t.isKey == true);
var paramList = columList.Where(t => t.isKey != true);
foreach (var k in keyList)
{
Debug.Log("Key is : " + k.name);
//string key_param = param_template.Replace("[param]", masterNameInUpper);
template_file_data = template_file_data.Replace("[key]", k.name);
template_file_data = template_file_data.Replace("[Key]", GetUpperName(k.name));
if (IsInt(k.type))
{
template_file_data = template_file_data.Replace("[key_type]", "int");
}
else if (IsString(k.type))
{
template_file_data = template_file_data.Replace("[key_type]", "string");
}
}
foreach (var param in paramList)
{
string paramNamaInUpper = GetUpperName(param.name);
string tmpStr = param_template.Replace("[param]", param.name);
if (IsInt(param.type))
{
tmpStr = tmpStr.Replace("[param_type]", "int");
}
else if (IsString(param.type))
{
tmpStr = tmpStr.Replace("[param_type]", "string");
}
param_str += tmpStr.Replace("[Param]", paramNamaInUpper);
}
template_file_data = template_file_data.Replace(ParamListStr, param_str);
string fileName = string.Format(@"{0}\{1}.cs", outputFilePath, masterNameInUpper);
Debug.Log("output : " + fileName);
File.WriteAllText(fileName, template_file_data);
}
/// <summary>
/// 包含多个主键的配置表
/// </summary>
/// <param name="sheet"></param>
/// <param name="columList"></param>
private static void ConvertTwoMoreKeyMaster(DataTable sheet, List<ColumData> columList, int keyNum)
{
string masterNameInLower = sheet.TableName;
string masterNameInUpper = GetUpperName(masterNameInLower);
Debug.Log("master class 名 : " + masterNameInLower + " / " + masterNameInUpper);
string appPath = Application.dataPath;
string template_file_path = appPath + TemplatePath + TemplateTwoKeyFile;
if (keyNum == 3)
{
template_file_path = appPath + TemplatePath + TemplateThreeKeyFile;
}
if (keyNum == 4)
{
template_file_path = appPath + TemplatePath + TemplateFourKeyFile;
}
Debug.Log("template file path : " + template_file_path);
if (!System.IO.File.Exists(template_file_path))
{
Debug.LogWarning("not find template!");
return;
}
string template_file_data = string.Empty;
using (System.IO.StreamReader sr = new System.IO.StreamReader(template_file_path))
{
template_file_data = sr.ReadToEnd();
}
template_file_data = template_file_data.Replace(MasterUpperNameReplaceStr, masterNameInUpper);
template_file_data = template_file_data.Replace(MasterLowerNameReplaceStr, masterNameInLower);
string template_param_file_path = appPath + TemplatePath + TemplateParamFile;
string param_template = "";
string param_str = "";
using (System.IO.StreamReader sr = new System.IO.StreamReader(template_param_file_path))
{
param_template = sr.ReadToEnd();
}
var keyList = columList.Where(t => t.isKey == true);
var paramList = columList.Where(t => t.isKey != true);
int keyCnt = 1;
foreach (var k in keyList)
{
Debug.Log("Key" + keyCnt + " is : " + k.name);
template_file_data = template_file_data.Replace("[key" + keyCnt + "]", k.name);
template_file_data = template_file_data.Replace("[Key" + keyCnt + "]", GetUpperName(k.name));
if (IsInt(k.type))
{
template_file_data = template_file_data.Replace("[key_type" + keyCnt + "]", "int");
}
else if (IsString(k.type))
{
template_file_data = template_file_data.Replace("[key_type" + keyCnt + "]", "string");
}
keyCnt++;
}
foreach (var param in paramList)
{
string paramNamaInUpper = GetUpperName(param.name);
string tmpStr = param_template.Replace("[param]", param.name);
if (IsInt(param.type))
{
tmpStr = tmpStr.Replace("[param_type]", "int");
}
else if (IsString(param.type))
{
tmpStr = tmpStr.Replace("[param_type]", "string");
}
param_str += tmpStr.Replace("[Param]", paramNamaInUpper);
}
template_file_data = template_file_data.Replace(ParamListStr, param_str);
string fileName = string.Format(@"{0}\{1}.cs", outputFilePath, masterNameInUpper);
Debug.Log("output : " + fileName);
File.WriteAllText(fileName, template_file_data);
}
private static string GetUpperName(string name)
{
string[] tmpNameArray = name.Split('_');
string nameInUpper = "";
System.Globalization.TextInfo ti = System.Globalization.CultureInfo.CurrentCulture.TextInfo;
foreach (var t in tmpNameArray)
{
nameInUpper += ti.ToTitleCase(t);
}
return nameInUpper;
}
private static bool IsInt(string typeName)
{
if (typeName.ToLower().Contains("int") || typeName.ToLower().Contains("timestamp"))
{
return true;
}
return false;
}
private static bool IsString(string typeName)
{
if (typeName.ToLower().Contains("string") || typeName.ToLower().Contains("time") || typeName.ToLower().Contains("text"))
{
return true;
}
return false;
}
}
public class ColumData
{
public string name;
public string type;
public bool isKey;
public ColumData(string _name, string _type, bool _isKey)
{
name = _name;
type = _type;
isKey = _isKey;
}
}
}
转换时候用到的模板文件 template_1key.txt
/*******************************************
* 从主 Excel 自动生成的文件 *
* 不要手动修改该文件! *
*******************************************/
using System.Collections.ObjectModel;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
namespace Master
{
public class [MasterName]Data : ISerializationCallbackReceiver
{
/// <summary>
/// 序列化列表
/// </summary>
[SerializeField]
private List<[MasterName]DataFormat> [mastername];
/// <summary>
/// 私有Dictionary
/// </summary>
private ReadOnlyDictionary<[key_type], [MasterName]DataFormat> _[mastername];
/// <summary>
/// 属性Dictionary
/// key:[key]
/// </summary>
public ReadOnlyDictionary<[key_type], [MasterName]DataFormat> [MasterName]Dic { get { return _[mastername]; } }
public void OnAfterDeserialize()
{
if (_[mastername] != null)
{
_[mastername] = null;
}
_[mastername] = new ReadOnlyDictionary<[key_type], [MasterName]DataFormat>([mastername].ToDictionary(key => key.[Key], value => value));
}
public void OnBeforeSerialize()
{
}
[Serializable]
public class [MasterName]DataFormat
{
[SerializeField]
private [key_type] [key];
public [key_type] [Key] { get { return [key]; } }
[paramList]
}
}
}
template_2key.txt
/*******************************************
* 从主 Excel 自动生成的文件 *
* 不要手动修改该文件! *
*******************************************/
using System.Collections.ObjectModel;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
namespace Master
{
public class [MasterName]Data : ISerializationCallbackReceiver
{
/ <summary>
/// 序列化列表
/// </summary>
[SerializeField]
private List<[MasterName]DataFormat> [mastername];
/// <summary>
/// 私有Dictionary
/// </summary>
private ReadOnlyDictionary<[key_type1], [MasterName]DataFormat> _[mastername];
/// <summary>
/// 属性Dictionary
/// key:unit id
/// </summary>
public ReadOnlyDictionary<[key_type1], [MasterName]DataFormat> [MasterName]Dic { get { return _[mastername]; } }
public void OnAfterDeserialize()
{
if (_[mastername] != null)
{
_[mastername] = null;
}
_[mastername] = new ReadOnlyDictionary<[key_type1], [MasterName]DataFormat>([mastername].ToDictionary(key => key.[Key1], value => value));
}
public void OnBeforeSerialize()
{
}
[Serializable]
public class [MasterName]DataFormat : ISerializationCallbackReceiver
{
[SerializeField]
private [key_type1] [key1];
public [key_type1] [Key1] { get { return [key1]; } }
/ <summary>
/// 序列化列表
/// </summary>
[SerializeField]
private List<[MasterName]IndexFormat> index_list;
/// <summary>
/// 私有Dictionary
/// </summary>
private ReadOnlyDictionary<[key_type2], [MasterName]IndexFormat> _index_list;
/// <summary>
/// 属性Dictionary
/// key:unit id
/// </summary>
public ReadOnlyDictionary<[key_type2], [MasterName]IndexFormat> Index { get { return _index_list; } }
public void OnAfterDeserialize()
{
if (_index_list != null)
{
_index_list = null;
}
_index_list = new ReadOnlyDictionary<[key_type2], [MasterName]IndexFormat>(index_list.ToDictionary(key => key.[Key2], value => value));
}
public void OnBeforeSerialize()
{
}
}
[Serializable]
public class [MasterName]IndexFormat
{
[SerializeField]
private [key_type2] [key2];
public [key_type2] [Key2] { get { return [key2]; } }
[paramList]
}
}
}
三、运行过程中读取json文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ConfigManger : MonoBehaviour
{
public TextAsset fonfigJson;
void Start()
{
string content = fonfigJson.text;
Master.UnitData unitData = JsonUtility.FromJson<Master.UnitData>(content);
Debug.Log(unitData.UnitDic.Count);
foreach (var item in unitData.UnitDic)
{
Debug.Log(item.Value.Name);
}
}
}
资源下载地址: 前往下载