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

news2024/11/20 6:21:35

        今天来介绍一下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");
			else
				stringBuilder.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.coloradmin.cn/o/1798842.html

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

相关文章

为Android组件化项目搭建Maven私服

概览 文章目录 概览前言搭建 maven 私服服务器环境jdk安装配置nexus安装配置管理创建存储点、仓库 项目中使用 maven 私服上传 module 到仓库自动发布 module手动上传单个aar包 引用仓库中的 modulebuild.gradle引入远程module FAQ开发阶段有些module用远程依赖&#xff0c;有些…

苹果警告部分 iPhone 用户称他们遭到雇佣间谍软件攻击

苹果警告部分 iPhone 用户称他们遭到“雇佣间谍软件攻击 苹果正在提醒用户注意针对 iPhone 的新一轮已识别雇佣间谍软件攻击。可能的受害者已经收到来自苹果的电子邮件&#xff0c;其中描述了该攻击如何“远程破坏 iPhone”。据路透社报道&#xff0c;印度和其他 91 个国家的受…

内容产品运营方案业务架构解析与实践探索

### 背景 在信息爆炸的时代背景下&#xff0c;内容产品运营成为各行各业竞争的重要环节。构建合理的内容产品运营方案业务架构&#xff0c;能够帮助企业更好地管理内容生产、推广和变现&#xff0c;提升品牌影响力和商业价值。 ### 业务架构设计 #### 1. 内容生产与管理 建立…

一套java开发的(未来工厂核心MES系统成品源码)技术架构:java+springboot 支撑多端管理,可商用

MES定义为“位于上层的计划管理系统与底层的工业控制之间的面向车间层的管理信息系统” 20世纪90年代初期&#xff0c;中国就开始对MES以及ERP的跟踪研究、告知或试点&#xff0c;而且曾经发言 “管控一体化”&#xff0c;“人、财、物、产、供、销”等颇具中国独具一格的CIMS、…

input组件 type为nickname pc端获取不到这个绑定的值?

一、input组件 type为nickname pc端获取不到这个绑定的值&#xff1f; 在pc端 使用input blur 事件获取选择昵称结果失败 代码如下&#xff1a; <input type"nickname" bindblur"binname" name"nickName" placeholder"请输入昵称"…

2024年政治经济学与社会科学国际会议(ICPESS 2024)

2024年政治经济学与社会科学国际会议 2024 International Conference on Political Economy and Social Sciences 会议简介 2024年政治经济学与社会科学国际会议是一个致力于探讨政治经济学与社会科学交叉领域前沿问题的国际盛会。本次会议汇聚了全球顶尖的专家学者、研究人员和…

传统产品经理AI产品经理

前言 随着科技的发展&#xff0c;技术的革新&#xff0c;AI技术当今已经渗入到各个行业里边&#xff0c;身处其中的产品经理也面临的新的挑战和机遇&#xff0c;下面是笔者整理分享的关于传统的产品经理如何顺应时代发展&#xff0c;成功转换成AI产品经理的相关内容&#xff0…

vcruntime140.dll干嘛的?丢失了vcruntime140.dll要咋办?

vcruntime140.dll干嘛的&#xff1f;vcruntime140.dll就是一个dll文件&#xff0c;它对于很多程序都是有用的&#xff0c;如果没有了它&#xff0c;那么你的有些程序是打不开的&#xff01;所以当你丢失的时候&#xff0c;你就要想办法去修复vcruntime140.dll文件&#xff0c;假…

那个会用AI绘画的设计师,刚刚加薪了!不会AI的打工人却只能被优化?

大家好&#xff0c;我是向阳。 随着ChatGPT引领人工智能的热潮&#xff0c;AI绘画也悄然崭露头角&#xff01; 插画师、建筑师、平面设计师等艺术创作领域的从业者&#xff0c;感受到了前所未有的压力 当一个设计师能有多难&#xff1f; 设计师需要在&#xff1a;主管/经理…

SQL面试问题集

目录 Q.左连接和右连接的区别 Q.union 和 union all的区别 1、取结果的交集 2、获取结果后的操作 Q.熟悉开窗函数吗&#xff1f;讲一下row_number和dense_rank的区别。 Q.hive行转列怎么操作的 Q.要求手写的题主要考了聚合函数和窗口函数&#xff0c;row_number()&#…

(2024,ViT,小波变换,图像标记器,稀疏张量)基于小波的 ViT 图像标记器

Wavelet-Based Image Tokenizer for Vision Transformers 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0 摘要 1 引言 3 基于小波的图像压缩简介 4 图像标记器 4.1 像素空间标记嵌…

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

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

AWS S3存储桶中如何下载文件

AWS S3存储桶中如何下载文件 1.单个下载 AWS S3 控制台提供了下载单个文件的功能&#xff0c;但是不支持直接在控制台中进行批量下载文件。您可以通过以下步骤在 AWS S3 控制台上下载单个文件&#xff1a;   1.1登录 AWS 管理控制台。   1.2转到 S3 服务页面。   1.3单击…

seerfar丨OZON运营工具,OZON选品插件

随着全球电商市场的蓬勃发展&#xff0c;OZON作为俄罗斯及东欧地区的重要电商平台&#xff0c;吸引了众多中国商家的目光。然而&#xff0c;如何在OZON平台上脱颖而出&#xff0c;实现高效的商品运营&#xff0c;成为了众多商家亟待解决的问题。在这样的背景下&#xff0c;seer…

流批一体计算引擎-10-[Flink]中的常用算子和DataStream转换

pyflink 处理 kafka数据 1 DataStream API 示例代码 从非空集合中读取数据&#xff0c;并将结果写入本地文件系统。 from pyflink.common.serialization import Encoder from pyflink.common.typeinfo import Types from pyflink.datastream import StreamExecutionEnviron…

什么是阴道菌群CST分型,不同的分型代表哪些女性健康问题

谷禾健康 人体内的各个部位&#xff0c;如皮肤、口腔、肠道和阴道等&#xff0c;都是微生物的重要栖息地&#xff0c;这些微生物与人体健康紧密相关&#xff0c;并能反映人体的疾病状态。这些部位因受基因、环境和生活方式等影响&#xff0c;具有独特的菌群特征。 女性生殖系统…

Linux磁盘分区(fdisk)和卷管理详解(VG-LV-PV)

先看整体图&#xff0c;再讲解概念 一、磁盘分区 一个磁盘disk可以分多个区part&#xff0c;用fdisk命令&#xff0c;举例把/dev/vdb划分为/dev/vdb1和/dev/vdb2 二、创建虚拟卷 LVM是逻辑盘卷管理&#xff08;Logical Volume Manager&#xff09;的简称&#xff0c;他是磁盘…

Cortex-M7——NVIC

Cortex-M7——NVIC 小狼http://blog.csdn.net/xiaolangyangyang 一、NVIC架构 二、中断及异常编号 三、中断屏蔽寄存器&#xff08;__disable_irq和__enable_irq操作的是PRIMASK寄存器&#xff09; 四、中断分组寄存器&#xff08;SCB->AIRCR[10:8]&#xff09; 五、NVIC寄…

「动态规划」如何求最小路径和?

64. 最小路径和https://leetcode.cn/problems/minimum-path-sum/description/ 给定一个包含非负整数的m x n网格grid&#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。说明&#xff1a;每次只能向下或者向右移动一步。 输入&#xff1a;…

DNF手游攻略:主C职业推荐,云手机强力辅助!

在《地下城与勇士》手游中&#xff0c;你是否厌倦了重复刷图和无休止的手动操作&#xff1f;利用VMOS云手机&#xff0c;你可以一键解决这些烦恼&#xff0c;实现自动打怪、一机多开&#xff0c;让游戏变得更加轻松愉快。下面我们将介绍如何使用VMOS云手机&#xff0c;以及推荐…