【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");
			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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谁懂啊!第一次用AI绘画做表情包,居然直接爆收入了!

大家好&#xff0c;我是设计师阿威 我的第一套表情包上周六上午11点终于在微信的表情商店上架啦&#xff01; 为什么说“终于”&#xff1f; 那是因为背后是无数次的努力–>被退回–>反复修改–>再提交–>再被退回–>再精心修改–>终于通过啦&#xff01;…

Python实现调用并执行Linux系统命令

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

Pyramid Vision Transformer, PVT(ICCV 2021)原理与代码解读

paper&#xff1a;Pyramid Vision Transformer: A Versatile Backbone for Dense Prediction without Convolutions official implementation&#xff1a;GitHub - whai362/PVT: Official implementation of PVT series 存在的问题 现有的 Vision Transformer (ViT) 主要设计…

豆包引领AI大模型PC端新潮流,预示行业薪资待遇与就业前景的广阔前景

前言 在AI大模型技术迅速发展的浪潮中&#xff0c;豆包AI助手凭借其独特的PC端布局&#xff0c;成为了行业的先行者。这一举措不仅体现了对市场需求和用户习惯的深度洞察&#xff0c;更预示着AI大模型领域薪资待遇和就业前景的广阔空间。 豆包AI助手通过推出PC客户端&#x…

tomcat-valve通过servlet处理请求

上一节说到请求url定位servlet的过程&#xff0c;tomcat会把请求url和容器的映射关系保存到MappingData中&#xff0c;org.apache.catalina.connector.Request类实现了HttpServletRequest&#xff0c;其中定义了属性mappingDataprotected final MappingData mappingData new M…

国产Sora免费体验-快手旗下可灵大模型发布

自从OpenAI公布了Sora后&#xff0c;震爆了全世界&#xff0c;但由于其技术的不成熟和应用的局限性&#xff0c;未能大规模推广&#xff0c;只有零零散散的几个公布出来的一些视频。昨日&#xff0c;快手成立13周年&#xff0c;可灵&#xff08;Kling&#xff09;大模型发布&am…

【vue3|第7期】 toRefs 与 toRef 的深入剖析

日期&#xff1a;2024年6月6日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xff…

vs2017中C2440错误:“初始化”:无法从const char[6]转换为char*问题解决

本文摘要&#xff1a;本文已解决 Python FileNotFoundError 的相关报错问题&#xff0c;并总结提出了几种可用解决方案。同时结合人工智能GPT排除可能得隐患及错误。 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领…

LLM系列: LLama2

推理流程 从输入文本&#xff0c;到推理输出文本&#xff0c;LLama2模型处理流程如下&#xff1a; step1 Tokenization 输入数据&#xff1a;一个句子或一段话。通常表示成单词或字符序列。 Tokenization即对文本按单词或字符序列切分&#xff0c;形成Token序列。Token序列再…

【Vue2源码学习分析】

# 文件结构 源码目录 # 调试环境搭建 安装依赖: npm i安装rollup: npm i -g rollup修改dev脚本&#xff0c;添加sourcemap&#xff0c;package.json "dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web- full-dev",运行开发命令…

LabVIEW阀性能试验台测控系统

本项目开发的阀性能试验台测控系统是为满足国家和企业相关标准而设计的&#xff0c;主要用于汽车气压制动系统控制装置和调节装置等产品的综合性能测试。系统采用工控机控制&#xff0c;配置电器控制柜&#xff0c;实现运动控制、开关量控制及传感器信号采集&#xff0c;具备数…

后端进阶-分库分表

文章目录 为什么需要分库为什么需要分表 什么时候需要分库分表只需要分库只需要分表 分库分表解决方案垂直分库水平分库垂直分表水平分表 分库分表常用算法范围算法hash分片查表分片 分库分表模式客户端模式代理模式 今天跟着训练营学习了分库分表&#xff0c;整理了学习笔记。…

Spring系统学习 -Spring IOC 的XML管理Bean之bean的获取、依赖注入值的方式

在Spring框架中&#xff0c;XML配置是最传统和最常见的方式之一&#xff0c;用于管理Bean的创建、依赖注入和生命周期等。这个在Spring中我们使用算是常用的&#xff0c;我们需要根据Spring的基于XML管理Bean了解相关Spring中常用的获取bean的方式、依赖注入值的几种方式等等。…

C++ Thread多线程并发记录(8)生产者-消费者模型与信号量(条件变量)

一.生产者-消费者模型 生产者-消费者模型是一个十分经典的多线程并发协作模式。所谓的生产者-消费者&#xff0c;实际上包含了两类线程&#xff0c;一种是生产者线程用于生产数据&#xff0c;另一种是消费者线程用于消费数据&#xff0c;为了解耦生产者和消费者的关系&#xff…

苹果Safari怎么清理缓存?原来快速清除浏览器的历史记录那么容易

在数字化时代&#xff0c;互联网已经成为我们日常生活中不可或缺的一部分。我们使用各种设备&#xff0c;如智能手机、平板电脑和笔记本电脑来浏览网页、获取信息、娱乐和社交。而在这些设备中&#xff0c;iPhone无疑是最受欢迎的选择之一。iPhone搭载的Safari浏览器以其简洁的…

three.js官方案例(animation / multiple)webgl_animation_multiple.html学习笔记

目录 ​编辑 1 骨架工具&#xff08;SkeletonUtils&#xff09; 1.1 clone方法 2 蒙皮网格&#xff08;SkinnedMesh&#xff09; 3 自测 4 webgl_animation_multiple.html全部脚本 1 骨架工具&#xff08;SkeletonUtils&#xff09; 用于操控 Skeleton、 SkinnedMesh、和…

Spring AI 第二讲 之 Chat Model API 第八节Anthropic 3 Chat

Anthropic Claude 是一系列基础人工智能模型&#xff0c;可用于各种应用。对于开发人员和企业来说&#xff0c;您可以利用 API 访问&#xff0c;直接在 Anthropic 的人工智能基础架构之上进行构建。 Spring AI 支持用于同步和流式文本生成的 Anthropic 消息 API。 Anthropic …

因为宇宙一片漆黑,所以地球才有昼夜之分,宇宙为什么是黑的?

因为宇宙一片漆黑&#xff0c;所以地球才有昼夜之分&#xff0c;宇宙为什么是黑的&#xff1f; 地球为何会有昼夜之分&#xff1f; 乍一看&#xff0c;这个问题很是简单&#xff0c;当然是因为地球一直在自转了&#xff0c;当地球的一部分被太阳照射时就是白昼&#xff0c;而…

Servlet搭建博客系统

现在我们可以使用Servlet来搭建一个动态(前后端可以交互)的博客系统了(使用Hexo只能实现一个纯静态的网页,即只能在后台自己上传博客)。有一种"多年媳妇熬成婆"的感觉。 一、准备工作 首先创建好项目,引入相关依赖。具体过程在"Servlet的创建"中介绍了。…

【Vue】单页应用程序介绍

通常基于Vue去开发一整个网站&#xff0c;开发出来的这整个网站应用&#xff0c;我们都会叫做单页应用程序 概念 单页应用程序&#xff1a;SPA【Single Page Application】是指所有的功能都在一个html页面上实现 我们可以将页面共用的部分封装成组件&#xff0c;底下要切换的也…