前言
最近需要读取策划的配置表,查找了相关文章,发现内容都不甚详细,不是缺少了这个功能就是缺少了那个功能,遂决定自己动手写一个
包含的功能有:
1.生成或读取对应的类
2.根据表内数据生成Json数据文件
效果
准备
1.接入3个第三方库(2023.7.7更新,脚本也加入了网盘)
链接:https://pan.baidu.com/s/1PuvP6zHncRalvtHhqp-VtQ?pwd=2fj9
提取码:2fj9
把三个dll扔到Unity项目的Plugins里就行(还没有这个文件夹就手动创建一个)
2.一个表格
包含的内容为:①字段描述②字段名③字段类型④数据,前三个的顺序不重要,根据自己习惯来就行,不过这个不一样的话要稍加修改代码,修改哪下文会提到
正题
思路:
1.首先 考虑清楚流程是什么样的
第一步 我们读取excel表中的数据
第二步 创建或者获取类
第三步 把读取的数据转化成对应的类的列表 然后转成json
2.去实现相关方法
如何获取文件夹下的所有excel文件
想法是 获取所有文件 然后判断文件后缀 如果为excel则加入列表
public static List<FileInfo> GetAllExcel(string dirPath)
{
List<FileInfo> fileList = new List<FileInfo>();
if (!Directory.Exists(dirPath))
{
Debug.LogError("文件夹地址错误");
return null;
}
DirectoryInfo direction = new DirectoryInfo(dirPath);//获取文件夹,exportPath是文件夹的路径
FileInfo[] files = direction.GetFiles("*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; i++)
{
if (files[i].Name.EndsWith(".xlsx"))
{
if (!fileList.Contains(files[i]))
{
fileList.Add(files[i]);
}
}
}
return fileList;
}
如何读取数据
引入命名空间
using Microsoft.SqlServer.Server;
using Excel;
根据文件地址读取表的内容
public static DataRowCollection ReadExcel(string filePath, ref int columnNum, ref int rowNum)
{
FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
DataSet result = excelReader.AsDataSet();
//Tables[0] 下标0表示excel文件中第一张表的数据
columnNum = result.Tables[0].Columns.Count;
rowNum = result.Tables[0].Rows.Count;
stream.Close();
return result.Tables[0].Rows;
}
如何生成类
获取对应表的第二行和第三行的内容,第二行为属性名,第三行为类型,写入文件的方法很简单,就是像打字一样把内容输入进去,就会自动识别 如"public “+” "+“类型名” +“ ” +属性名 +“;” 这样就可以完成一行属性的定义,类名设定为表名
public static void AutoCreateClass(string filePath)
{
string fileName = Path.GetFileNameWithoutExtension(filePath);
string storeEntityPath= $"{m_EntitySavePath}/{fileName}.cs";
//获得表数据
int columnNum = 0, rowNum = 0;
DataRowCollection collect = ReadExcel(filePath, ref columnNum, ref rowNum);
StringBuilder sb = new StringBuilder();
sb.AppendLine($"\tpublic class {fileName}");
sb.AppendLine("\t{");
for (int i = 0; i < columnNum; i++)
{
sb.AppendLine($"\t\tpublic {collect[2][i].ToString()} {collect[1][i].ToString()};");
}
sb.AppendLine("\t}");
try
{
if (!Directory.Exists(m_EntitySavePath))
{
Directory.CreateDirectory(m_EntitySavePath);
}
if (!File.Exists(storeEntityPath))
{
File.Create(storeEntityPath).Dispose(); //避免资源占用
}
File.WriteAllText(storeEntityPath, sb.ToString());
}
catch (System.Exception e)
{
Debug.LogError($"Excel转json时创建对应的实体类出错,实体类为:{fileName},e:{e.Message}");
}
}
如何将数据转化成json
先读表,然后根据表名在程序集中找类(这里默认生成在Assembly-CSharp里面),没有类就创建类,有类就获取,创建一个对象,然后从第四行开始(因为我这边第四行开始是数据)遍历列,很类中的每个字段一一对应赋值,再将这个对象放入列表,如果想要获取数组,需要规定一个分隔符来分隔数据,这里分隔符设定为|
public void ToJson(string filePath)
{
string fileName = Path.GetFileNameWithoutExtension(filePath);
string storeJsonPath = $"{m_JsonSavePath}/{fileName}.json";
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
//获得表数据
int columnNum = 0, rowNum = 0;
DataRowCollection collect = ReadExcel(filePath, ref columnNum, ref rowNum);
List<System.Object> objList = new List<object>();
objList.Clear();
//获取当前实体类
Assembly ab = Assembly.Load("Assembly-CSharp");
Type type = ab.GetType(fileName);
if (type == null)
{
Debug.LogError("你还没有创建对应的实体类!");
return;
}
if (!Directory.Exists(m_JsonSavePath))
Directory.CreateDirectory(m_JsonSavePath);
//逐行添加数据 从第四行开始是数据
for (int i = 3; i < rowNum; i++)
{
//创建一个实体类
object obj = ab.CreateInstance(type.ToString());
for (int z = 0; z < columnNum; z++)
{
//获取表格中对应字段名的信息
FieldInfo info = type.GetField(collect[1][z].ToString());
//是数组
if (info.FieldType.IsArray)
{
string currentContext = collect[i][z].ToString();
string[] strs = currentContext.Split(separators, StringSplitOptions.RemoveEmptyEntries);
//数组内元素的类型
Type elementType = info.FieldType.GetElementType();
//创建数组
object array = Activator.CreateInstance(info.FieldType, new object[] { strs.Length });
MethodInfo setValue = info.FieldType.GetMethod("SetValue", new Type[2] { typeof(object), typeof(int) });
//给数组赋值
for (int m = 0; m < strs.Length; m++)
{
object v = Convert.ChangeType(strs[m], elementType);
setValue.Invoke(array, new object[] { v, m });
}
type.GetField(collect[1][z].ToString()).SetValue(obj, array);
}
//不是数组
else
{
//将表格中的数据转换为对应的数据类型
object value = Convert.ChangeType(collect[i][z].ToString(), info.FieldType);
//给对应的字段赋值
type.GetField(collect[1][z].ToString()).SetValue(obj, value);
}
}
objList.Add(obj);
}
//写入json文件
if (!File.Exists(storeJsonPath))
{
File.Create(storeJsonPath).Dispose();
}
File.WriteAllText(storeJsonPath, JsonConvert.SerializeObject(objList));
Debug.Log($"生成{fileName}Json文件成功");
}
}
最后就是一些编辑器扩展方面的
private static string m_JsonSavePath = "Json";
private static string m_EntitySavePath = "Entity";
private static string m_DirPath = "Excel";
private Vector2 scrollPos;
public static readonly char[] separators = { '|', ',' };
[MenuItem("EasyTools/CreateCS")]
static void OpenWindow()
{
ExcelHelper window = (ExcelHelper)EditorWindow.GetWindow(typeof(ExcelHelper));
window.Show();
}
private void OnEnable()
{
m_JsonSavePath= EditorPrefs.GetString("JsonSavePath");
m_EntitySavePath = EditorPrefs.GetString("EntitySavePath");
m_DirPath = EditorPrefs.GetString("DirPath");
}
private void OnGUI()
{
EditorGUI.BeginChangeCheck();
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
EditorGUILayout.BeginHorizontal();
GUILayout.Label("表存放目录: ");
GUILayout.TextField(m_DirPath);
if (GUILayout.Button("选择表存放目录"))
{
OpenFileSelectWindow_Dir();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
GUILayout.Label("实体存放目录: ");
GUILayout.TextField(m_EntitySavePath);
if (GUILayout.Button("选择实体所在目录"))
{
OpenFileSelectWindow_Entity();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
GUILayout.Label("Json存放目录: ");
GUILayout.TextField(m_JsonSavePath);
if (GUILayout.Button("选择Json存放目录"))
{
OpenFileSelectWindow_Json();
}
EditorGUILayout.EndHorizontal();
if (GUILayout.Button("生成实体类"))
{
CreateEntities();
}
if (GUILayout.Button("生成Json"))
{
ExcelToJson();
}
EditorGUILayout.EndScrollView();
if (EditorGUI.EndChangeCheck())
EditorPrefs.SetString("JsonSavePath",m_JsonSavePath);
EditorPrefs.SetString("EntitySavePath", m_EntitySavePath);
EditorPrefs.SetString("DirPath", m_DirPath);
}
private void OpenFileSelectWindow_Dir()
{
m_DirPath = EditorUtility.OpenFolderPanel("自定义标题", Application.dataPath, "默认文件名");
}
private void OpenFileSelectWindow_Json()
{
m_JsonSavePath = EditorUtility.OpenFolderPanel("自定义标题", Application.dataPath, "默认文件名");
}
private void OpenFileSelectWindow_Entity()
{
m_EntitySavePath = EditorUtility.OpenFolderPanel("自定义标题", Application.dataPath, "默认文件名");
}