【Framework系列】Excel转Json,配置表、导表工具介绍

        今天来介绍一下Framework系列的配置部分,这一部分归属于Framework-Design之中。读过《Framework系列介绍》的小伙伴应该了解整个Framework框架是由多个工程项目组成,没看过的小伙伴可以点击链接了解一下。

        Framework-Design设计的初衷是给策划同学用的,工程包含文档(Documents)和配置(Configs)两个目录。配置目录则包含配表工具(ToolExcel)和导表工具工程(ToolProject)两个部分。

配表工具

        我们先来介绍配表工具部分的内容。配表工具目录下包含配表目录(Excels)、客户端类目录(ClientClasses)、客户端Json目录(ClientJsons)、服务器类目录(ServerClasses)、服务器Json目录(ServerJsons)和导表工具(ExcelToJson.exe)

        配表目录(Excels)中放置的是Excel配置文件,每个配置文件会导出对应名称的类文件(.cs文件)和Json文件(.json文件)。当不需要导出某个配置的时候可以在文件名前面添加~符号,文件名包含~符号则可以忽略不导出。

        配表第一行为备注说明,在导出类文件时会成为成员变量的备注。

        配表第二行为字段名,在导出类文件时会用于生成成员变量名,在导出Json文件时会用于生成数据的Key。

        配表第三行为数据类型,包含bool,bool[],int,int[],float,float[],string,string[] 8种类型,下拉框选择无需手动填写。

        配表第四行为导出类型,包含null,client/server,client,server 4种类型,下拉框选择无需手动填写。null为不导出,client/server为导出前后端,client单导出前端,server单导出后端。

        配表第五行一下为数据, 数组数据用,符号分隔。

        配表完成之后可以运行ExcelToJson.exe控制台程序导出配置,前后端的类文件和Json文件会分别导出到对应目录,目录不存在会自动创建,无需手动创建。文件夹内的文件也会先清空在生产新的文件。

导表工具工程

        接下来介绍一下导表工具的具体实现。之前也有写过导表工具的文章,之前的导表工具是作为Unity的插件来设计的。由于在实际工作中配表工作大部分是有策划同学完成,并且配表数据并不单单只是前端使用,后端也需要用到配置数据,所以配表工具依附于Unity的设计并不合理。这一次的导表工具完全独立出来,作为一个单独的工程项目。

        导表工具的实现主要分为三个部分,第一是解析Excel文件,第二是生成类文件,第三是生成Json文件。由于代码比较多,文章里只截取重要部分,完整代码可以在文章最后的工程连接获取。代码中还有许多c#的文件操作方法,不太了解的同学可以自行查阅c#官方文档。

        

using ExcelDataReader;private string[] mDescriptionArray;
private string[] mFieldArray;
private string[] mTypeArray;
private string[] mPlatformArray;/// <summary>Excel结构枚举</summary>
public enum EnumExcelStruct
{/// <summary>描述</summary>Description = 0,/// <summary>字段名</summary>Field,/// <summary>类型</summary>Type,/// <summary>平台</summary>Platform,/// <summary>数据</summary>Data,
}/// <summary>解析配置</summary>
/// <param name="configPath">配置路径</param>
private void ParseConfig(string pConfigPath)
{FileStream stream = File.OpenRead(pConfigPath);IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);while (excelReader.Read()){if (excelReader.Depth == (int)EnumExcelStruct.Description){mDescriptionArray = GetDatas(excelReader);}else if (excelReader.Depth == (int)EnumExcelStruct.Field){mFieldArray = GetDatas(excelReader);}else if (excelReader.Depth == (int)EnumExcelStruct.Type){mTypeArray = GetDatas(excelReader);}else if(excelReader.Depth == (int)EnumExcelStruct.Platform){mPlatformArray = GetDatas(excelReader);}else{break;}}excelReader.Close();
}/// <summary>获取数据</summary>
/// <param name="excelReader">excelReader</param>
private string[] GetDatas(IExcelDataReader excelReader)
{string[] datas = new string[excelReader.FieldCount];for (int i = 0; i < excelReader.FieldCount; i++){datas[i] = excelReader.GetString(i);}return datas;
}

        这里主要展示的是解析Excel数据的代码。读取Excel数据需要用c#自带的ExcelDataReader库,通过using包含就可以使用了。通过ExcelReaderFactory.CreateOpenXmlReader接口获取IExcelDataReader对象,通过调用IExcelDataReader对象的Read接口会逐行读取Excel中的数据。这里为了后续生成类文件和Json文件做准备,所以将数据存入了不同的string[]中。

        IExcelDataReader在读取Excel数据时可以理解成在读取一个二维数组,每调用一次Read接口会读取一行里的数据,然后通过列索引获取对应数据。

using System.IO;
using System.Text;private string className;
private string[] mDescriptionArray;
private string[] mFieldArray;
private string[] mTypeArray;
private string[] mPlatformArray;
private StringBuilder stringBuilder = new StringBuilder();/// <summary>生成代码</summary>
private void GenerateCode()
{stringBuilder.Clear();stringBuilder.Append("/*Auto-create script.\n");stringBuilder.Append(" * Don't Edit it. */\n");stringBuilder.Append("\n");stringBuilder.Append("using System.Collections.Generic;\n");stringBuilder.Append("using Framework.Data;\n");stringBuilder.Append("\n");stringBuilder.Append("namespace Game.Config\n");stringBuilder.Append("{\n");stringBuilder.AppendFormat("\tpublic class {0} : ConfigBase\n", className);stringBuilder.Append("\t{\n");for (int i = 0; i < mDescriptionArray.Length; i++){if (CheckPlatform(mPlatformArray[i])){stringBuilder.AppendFormat("\t\t/// <summary>{0}</summary>\n", mDescriptionArray[i]);if (i == 0)stringBuilder.Append("\t\tpublic object id;\n");elsestringBuilder.AppendFormat("\t\tpublic {0} {1};\n", mTypeArray[i], mFieldArray[i]);}}stringBuilder.Append("\t}\n");stringBuilder.Append("}");
}/// <summary>输出文件</summary>
private void ExportFile()
{string path = string.Format("{0}/{1}.cs", mExportPath, className);string content = stringBuilder.ToString();File.WriteAllText(path, content);
}

        生成类文件的本质其实就是生成后缀名为.cs的文本文件,文本的编辑我们则使用到的是StringBuilder,文本编辑我们则使用到之前Excel解析出来的数据。编辑完成后将StringBuilder转换成string,最后通过File库将文件生成出来。

using System;
using System.IO;
using System.Text;
using ExcelDataReader;
using Newtonsoft.Json;namespace ExcelToJson
{public class JsonGenerator{private string mExportPath = "";private PlatformType mPlatformType = PlatformType.None;private string className;private string[] mFieldArray;private string[] mTypeArray;private string[] mPlatformArray;private string[] mDataArray;private StringBuilder stringBuilder;private JsonTextWriter jsonTextWriter;public void Init(string pExportPath, PlatformType pPlatformType){mExportPath = pExportPath;mPlatformType = pPlatformType;if (!Directory.Exists(mExportPath)){Directory.CreateDirectory(mExportPath);}}private void Reset(){stringBuilder = new StringBuilder();StringWriter stringWriter = new StringWriter(stringBuilder);jsonTextWriter = new JsonTextWriter(stringWriter);jsonTextWriter.Formatting = Formatting.Indented;}/// <summary>生成Json</summary>/// <param name="pConfigPath">配置路径</param>public void GenerateJson(FileSystemInfo pFileSystemInfo){if (File.Exists(pFileSystemInfo.FullName)){int index = pFileSystemInfo.Name.IndexOf(".");className = pFileSystemInfo.Name.Substring(0, index);Reset();GenerateJsonCode(pFileSystemInfo.FullName);ExportFile();}}/// <summary>生成Json代码</summary>/// <param name="pConfigPath">配置路径</param>private void GenerateJsonCode(string pConfigPath){FileStream stream = File.OpenRead(pConfigPath);IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);while (excelReader.Read()){if (excelReader.Depth == (int)EnumExcelStruct.Field){mFieldArray = GetDatas(excelReader);}else if (excelReader.Depth == (int)EnumExcelStruct.Type){mTypeArray = GetDatas(excelReader);}else if (excelReader.Depth == (int)EnumExcelStruct.Platform){mPlatformArray = GetDatas(excelReader);}else if (excelReader.Depth == (int)EnumExcelStruct.Data){if (!CheckPlatform(mPlatformArray[0]))return;WriteStart();mDataArray = GetDatas(excelReader);AppendJson(mTypeArray, mFieldArray, mPlatformArray, mDataArray);}else if (excelReader.Depth > (int)EnumExcelStruct.Data){mDataArray = GetDatas(excelReader);AppendJson(mTypeArray, mFieldArray, mPlatformArray, mDataArray);}}jsonTextWriter.WriteEnd();excelReader.Close();}/// <summary>写入开始</summary>private void WriteStart(){string type = mTypeArray[0];if (type == "int")jsonTextWriter.WriteStartArray();else if (type == "string")jsonTextWriter.WriteStartObject();}/// <summary>获取数据</summary>/// <param name="excelReader">excelReader</param>/// <returns></returns>private string[] GetDatas(IExcelDataReader excelReader){string[] datas = new string[excelReader.FieldCount];for (int i = 0; i < excelReader.FieldCount; i++){datas[i] = excelReader.GetString(i);}return datas;}private bool CheckPlatform(string pPlatformKey){if (mPlatformType == PlatformType.Client && (pPlatformKey == PlatformDefine.cCSKey || pPlatformKey == PlatformDefine.cCKey))return true;else if (mPlatformType == PlatformType.Server && (pPlatformKey == PlatformDefine.cCSKey || pPlatformKey == PlatformDefine.cSKey))return true;return false;}/// <summary>添加Json</summary>/// <param name="types">类型</param>/// <param name="fields">字段名</param>/// <param name="datas">数据</param>private void AppendJson(string[] types, string[] fields, string[] platform, string[] datas){if (types[0] == "string")jsonTextWriter.WritePropertyName(datas[0]);jsonTextWriter.WriteStartObject();for (int i = 0; i < types.Length; i++){if (!CheckPlatform(platform[i]))continue;switch (types[i]){case TypeDefine.cBool:AppendBool(fields[i], datas[i]);break;case TypeDefine.cBoolArray:AppendBoolArray(fields[i], datas[i]);break;case TypeDefine.cInt:AppendInt(fields[i], datas[i]);break;case TypeDefine.cIntArray:AppendIntArray(fields[i], datas[i]);break;case TypeDefine.cFloat:AppendFloat(fields[i], datas[i]);break;case TypeDefine.cFloatArray:AppendFloatArray(fields[i], datas[i]);break;case TypeDefine.cString:AppendString(fields[i], datas[i]);break;case TypeDefine.cStringArray:AppendStringArray(fields[i], datas[i]);break;}}jsonTextWriter.WriteEndObject();}private void AppendBool(string field, string data){jsonTextWriter.WritePropertyName(field);if (data == "true")jsonTextWriter.WriteValue(true);else if (data == "false")jsonTextWriter.WriteValue(false);}private void AppendBoolArray(string field, string data){jsonTextWriter.WritePropertyName(field);jsonTextWriter.WriteStartArray();data = data.Replace("[", "");data = data.Replace("]", "");string[] dataArray = data.Split(',');for (int i = 0; i < dataArray.Length; i++){if (dataArray[i] == "true")jsonTextWriter.WriteValue(true);else if (dataArray[i] == "false")jsonTextWriter.WriteValue(false);}jsonTextWriter.WriteEndArray();}private void AppendInt(string field, string data){jsonTextWriter.WritePropertyName(field);jsonTextWriter.WriteValue(int.Parse(data));}private void AppendIntArray(string field, string data){jsonTextWriter.WritePropertyName(field);jsonTextWriter.WriteStartArray();data = data.Replace("[", "");data = data.Replace("]", "");string[] dataArray = data.Split(',');for (int i = 0; i < dataArray.Length; i++){int value = int.Parse(dataArray[i]);jsonTextWriter.WriteValue(value);}jsonTextWriter.WriteEndArray();}private void AppendFloat(string field, string data){jsonTextWriter.WritePropertyName(field);jsonTextWriter.WriteValue(float.Parse(data));}private void AppendFloatArray(string field, string data){jsonTextWriter.WritePropertyName(field);jsonTextWriter.WriteStartArray();data = data.Replace("[", "");data = data.Replace("]", "");string[] dataArray = data.Split(',');for (int i = 0; i < dataArray.Length; i++){float value = float.Parse(dataArray[i]);jsonTextWriter.WriteValue(value);}jsonTextWriter.WriteEndArray();}private void AppendString(string field, string data){jsonTextWriter.WritePropertyName(field);jsonTextWriter.WriteValue(data);}private void AppendStringArray(string field, string data){jsonTextWriter.WritePropertyName(field);jsonTextWriter.WriteStartArray();data = data.Replace("[", "");data = data.Replace("]", "");string[] dataArray = data.Split(',');for (int i = 0; i < dataArray.Length; i++){jsonTextWriter.WriteValue(dataArray[i]);}jsonTextWriter.WriteEndArray();}/// <summary>输出文件</summary>private void ExportFile(){if (CheckPlatform(mPlatformArray[0])){string path = string.Format("{0}/{1}.json", mExportPath, className);string content = stringBuilder.ToString();File.WriteAllText(path, content);}}}
}

        与类文件相同,Json文件生成的实质也是生成一个后缀名为.json的文件。除了StringBuilder之外生成json文件还需要用到JsonTextWriter类,使用using包含Newtonsoft.Json库就能使用了。关于JsonTextWriter中的接口小伙伴可以自行查阅接口。

官方文档链接

ExcelDataReader链接:https://github.com/ExcelDataReader/ExcelDataReader

Newtonsoft.Json链接:https://www.newtonsoft.com/json

Newtonsoft.Json文档链接:https://www.newtonsoft.com/json/help/html/Introduction.htm

C#相关类文档链接:文件和流 I/O - .NET | Microsoft Learn、File 类 (System.IO) | Microsoft Learn、Directory 类 (System.IO) | Microsoft Learn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/24221.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上市公司绿色并购数据+do文件(1996-2024.4)

数据简介&#xff1a;手工搜集重污染上市公司的并购公告&#xff0c;采用内容分析法&#xff0c;对每次并购的背景和目的&#xff0c;主并企业和标的企业经营范围以及该次并购对主并企业带来的影响进行综合分析&#xff0c;逐一判断该项并购事件是否为绿色并购 时间跨度&#…

Python | 洗盘子(栈)

栈的基本概念&#xff08;空栈、栈顶、栈底&#xff09;和特点&#xff08;先入后出&#xff09; Python 语言确实支持栈数据结构&#xff0c;但它通常是通过列表来模拟实现的。 获取栈的长度&#xff0c;即栈中元素的数量&#xff0c;这通过len()获取列表的长度来实现。进栈…

汽车尾气排放污染的解决方案

根据公安部截至2023年底的机动车市场保有量统计&#xff0c;燃油车市场仍有不少消费者拥趸&#xff1a;目前全国新能源汽车保有量仅占汽车总量的6.07%&#xff0c;而其中的纯电动汽车保有量占比仅为76.05%。 汽车尾气排放污染已成为城市主要污染源之一。据统计显示&#xff0c…

[力扣题解] 28. 找出字符串中第一个匹配项的下标

题目&#xff1a;28. 找出字符串中第一个匹配项的下标 思路 观察法&#xff08;呵呵呵&#xff09; 代码 class Solution { public:int strStr(string haystack, string needle) {if(needle.empty()){return 0;}int i, j 0, x1, x2;for(i 0; i < haystack.size(); i){…

点盾云鹏保宝金狮金盾加密视频录屏翻录破解使用方法

在我们录网课的时候&#xff0c;通常录屏工具都会被网课播放器检测。 可以用以下程序。 这款软件采用独家方法特殊方式打开录屏工具&#xff0c;理论上通杀所有的检测进程的加密视频播放器的检测&#xff0c;不被检测。 获取&#xff1a; spjm.vip/sp/pz/wnlp.txt 使用方法…

python对视频进行帧处理以及裁减部分区域

视频截取帧 废话不多说直接上代码&#xff1a; from cv2 import VideoCapture from cv2 import imwrite# 定义保存图片函数 # image:要保存的图片名字 # addr&#xff1b;图片地址与相片名字的前部分 # num: 相片&#xff0c;名字的后缀。int 类型 def save_image(image, add…

嵌入式Linux系统编程 — 2.1 标准I/O库简介

目录 1 标准I/O库简介 1.1 标准I/O库简介 1.2 标准 I/O 和文件 I/O 的区别 2 FILE 指针 3 标准I/O库的主要函数简介 4 标准输入、标准输出和标准错误 4.1 标准输入、标准输出和标准错误概念 4.2 示例程序 5 打开文件fopen() 5.1 fopen()函数简介 5.2 新建文件的权限…

时间序列新范式!多尺度+时间序列,刷爆多项SOTA

当我们面对复杂模式和多变周期的应用场景&#xff08;比如金融市场分析&#xff09;时&#xff0c;采用多尺度时间序列来做分析和预测是个更好的选择。 这是因为&#xff1a;传统时序方法通常只用固定时间窗口来提取信息&#xff0c;难以适应不同时间尺度上的模式变化。但多尺…

全程自动化操作 自动生成图文发布,矩阵批量软件系统 日产1-3万篇

一、简介 图文发布对于现代网站运营至关重要&#xff0c;然而手动创建和发布图文内容效率低下且易出错。全自动化图文生成发布流程可以解决这个问题。本文将详细说明如何以编程方式实现这一流程。 二、模块设计 该流程主要包含三个模块&#xff1a;图像生成&#xff0c;文本生成…

python-df的合并与Matplotlib绘图

1 数据连接 concat merge join &#xff08;append 作为了解&#xff09; append 竖直方向追加&#xff0c; 在最新的pandas版本中已经被删除掉了&#xff0c; 这里推荐使用concat 1.1 pd.concat 两张表&#xff0c; 通过行名、列名对齐进行连接 import pandas as pd df1 …

apifox 生成签名

目录 前言准备编写签名脚本签名说明捋清思路编码获取签名所需的参数生成签名将签名放到合适的位置完整代码 在apifox中配置脚本新增公共脚本引用公共脚本添加环境变量 参考 前言 略 准备 查看apifox提供的最佳实践文章&#xff1a;接口签名如何处理 编写签名脚本 签名说明…

力扣算法题:打家劫舍 -- 多语言实现

这题目应该是翻译有问题或者我的理解有问题。。。按照题目给的不相邻的盗取逻辑运行正确,但是提交报错,如果使用全部进入但是拿最多钱的逻辑却正确了。。。 好家伙,挨家挨户走一遍不久触发报警了么?咋还正确了? "如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动…

Ant Design Pro

一&#xff1a;Ant Design pro是什么&#xff1a; Ant Design Pro 是基于 Ant Design 和 umi 的封装的一整套企业级中后台前端/设计解决方案&#xff0c;致力于在设计规范和基础组件的基础上&#xff0c;继续向上构建&#xff0c;提炼出典型模板/业务组件/配套设计资源&#x…

【JMeter接口测试工具】第二节.JMeter基本功能介绍(中)【入门篇】

文章目录 前言四、信息头管理器五、Jmeter参数化 5.1 用户自定义的变量 5.2 csv批量添加 5.3 用户参数 5.4 随机数函数 5.5 计数器函数 5.6 时间函数六、Jmeter断言 6.0 断言介绍 6.1 响应断言 6.2 大小断言 6.3 持续时间断…

【Python机器学习】主成分分析(PCA)

主成分分析&#xff08;PCA&#xff09;是一种旋转数据集的方法&#xff0c;旋转后的数特征在统计上不相关。在做完这种旋转之后&#xff0c;通常是根据新特征对解释数据的重要性来选择它的一个子集。 举例&#xff1a; import mglearn.plots import matplotlib.pyplot as pl…

逐步更新动画混合参数(Blend)使其平滑地过渡到目标值

1.具体实现 逐步更新一个动画混合参数&#xff08;Blend&#xff09;&#xff0c;使其平滑地过渡到目标值&#xff0c;可以实现角色动作的平滑过渡&#xff0c;比如从走路过渡到跑步。 private float currentBleng;private float targetBlend;public float accelerSpeed 5;//…

(delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(标准类的泛型方法)

14.2.2 标准类的泛型方法 ​ 使用泛型类型定义类可能是最常见的情况&#xff0c;但泛型类型也可以用于非泛型类。换句话说&#xff0c;一个普通的类也可以有一个泛型方法。在这种情况下&#xff0c;不仅要在创建类的实例时为泛型占位符指定类型&#xff0c;还要在调用方法时指…

OCP学习笔记-007 SQL语言之一:DQL

1. DQL - Data Query Language 命令行提示符修改 SQL> set time on 10:33:58 SQL> define DEFINE _DATE = "11-DEC-22" (CHAR) DEFINE _CONNECT_IDENTIFIER = "orcl" (CHAR) DEFINE _USER = "SYS" (CHAR) DEFINE _P…

python tqdm怎么安装

tqdm是一个显示循环的进度条的库。taqadum, تقدّم&#xff09;在阿拉伯语中的意思是进展。tqdm可以在长循环中添加一个进度提示信息&#xff0c;用户只需要封装任意的迭代器 tqdm(iterator)&#xff0c;是一个快速、扩展性强的进度条工具库。 tqdm库的安装 在CMD窗口下输…

利用梯度提升树分类法实现乳腺癌数据集分类

目录 1. 作者介绍2. 梯度提升树算法2.1 Boosting 算法2.2 Boosting Tree &#xff08;提升树&#xff09;2.3 梯度提升树&#xff08;Gradient Boosting Tree&#xff09; 3. 利用梯度提升树分类法实现乳腺癌数据集分类实验3.1 乳腺癌数据集介绍3.2 实验过程3.3 实验结果3.4 完…