【简单实用框架】【读Excel表】【可移植】

news2024/11/25 0:55:03

在这里插入图片描述

☀️博客主页:CSDN博客主页
💨本文由 我是小狼君 原创,首发于 CSDN💢
🔥学习专栏推荐:面试汇总
❗️游戏框架专栏推荐:游戏实用框架专栏
⛅️点赞 👍 收藏 ⭐留言 📝,如有错误请指正
📆 未来很长,值得我们全力奔赴更美好的生活✨


在这里插入图片描述Unity 小科普

老规矩,先介绍一下Unity的科普小知识:​​​​​​

  • Unity 是行业领先的实时3D开发平台。
  • 包括游戏开发,电影,AR/VR,虚拟现实在内的所有创作者,可以将梦想照进现实。
  • Unity提供了一套完整完善的软件解决方案,可用于创作,运营和模拟任何2D和3D的内容,进本全平台支持。

简单实用框架

目的:游戏开发中,经常会用到读表这个功能,一些配置数据都是放在表格中交给策划配置,这次分享的就是一个可快速移植的读表功能

原理:

经过了一个中间XMl的转换,极其方便使用,一个脚本搞定。

源码

using System.IO;
using Excel;
using System.Data;
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Table;
using System;
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Excel生成bytes和cs工具
/// </summary>
public class Excel2CsBytesTool
{
    static string ExcelDataPath = Application.dataPath + "/../ExcelData";//源Excel文件夹,xlsx格式
    static string BytesDataPath = Application.dataPath + "/Resources/DataTable";//生成的bytes文件夹
    static string CsClassPath = Application.dataPath + "/Scripts/DataTable";//生成的c#脚本文件夹
    static string XmlDataPath = ExcelDataPath + "/tempXmlData";//生成的xml(临时)文件夹..
    static string AllCsHead = "all";//序列化结构体的数组类.类名前缀

    static char ArrayTypeSplitChar = '#';//数组类型值拆分符: int[] 1#2#34 string[] 你好#再见 bool[] true#false ...
    static bool IsDeleteXmlInFinish = true;//生成bytes后是否删除中间文件xml

    [MenuItem("SDGSupporter/Excel/Excel2Cs")]
    static void Excel2Cs()
    {
        Init();
        Excel2CsOrXml(true);
    }

    [MenuItem("SDGSupporter/Excel/Excel2Bytes")]
    static void Excel2Xml2Bytes()
    {
        Init();
        //生成中间文件xml
        Excel2CsOrXml(false);
        //生成bytes
        WriteBytes();
    }

    static void Init()
    {
        if (!Directory.Exists(CsClassPath))
        {
            Directory.CreateDirectory(CsClassPath);
        }
        if (!Directory.Exists(XmlDataPath))
        {
            Directory.CreateDirectory(XmlDataPath);
        }
        if (!Directory.Exists(BytesDataPath))
        {
            Directory.CreateDirectory(BytesDataPath);
        }
    }

    static void WriteCs(string className, string[] names, string[] types, string[] descs)
    {
        try
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine("using System;");
            stringBuilder.AppendLine("using System.Collections.Generic;");
            stringBuilder.AppendLine("using System.IO;");
            stringBuilder.AppendLine("using System.Runtime.Serialization.Formatters.Binary;");
            stringBuilder.AppendLine("using System.Xml.Serialization;");
            stringBuilder.Append("\n");
            stringBuilder.AppendLine("namespace Table");
            stringBuilder.AppendLine("{");
            stringBuilder.AppendLine("    [Serializable]");
            stringBuilder.AppendLine("    public class " + className);
            stringBuilder.AppendLine("    {");
            for (int i = 0; i < names.Length; i++)
            {
                stringBuilder.AppendLine("        /// <summary>");
                stringBuilder.AppendLine("        /// " + descs[i]);
                stringBuilder.AppendLine("        /// </summary>");
                stringBuilder.AppendLine("        [XmlAttribute(\"" + names[i] + "\")]");

                string type = types[i];
                if (type.Contains("[]"))
                {
                    //type = type.Replace("[]", "");
                    //stringBuilder.AppendLine("        public List<" + type + "> " + names[i] + ";");

                    //可选代码:
                    //用_name字段去反序列化,name取_name.item的值,直接返回list<type>。
                    //因为xml每行可能有多个数组字段,这样就多了一层变量item,所以访问的时候需要.item才能取到list<type>
                    //因此用额外的一个变量直接返回List<type>。
                    type = type.Replace("[]", "");
                    stringBuilder.AppendLine("        public List<" + type + "> " + names[i] + "");
                    stringBuilder.AppendLine("        {");
                    stringBuilder.AppendLine("            get");
                    stringBuilder.AppendLine("            {");
                    stringBuilder.AppendLine("                if (_" + names[i] + " != null)");
                    stringBuilder.AppendLine("                {");
                    stringBuilder.AppendLine("                    return _" + names[i] + ".item;");
                    stringBuilder.AppendLine("                }");
                    stringBuilder.AppendLine("                return null;");
                    stringBuilder.AppendLine("            }");
                    stringBuilder.AppendLine("        }");
                    stringBuilder.AppendLine("        [XmlElementAttribute(\"" + names[i] + "\")]");
                    stringBuilder.AppendLine("        public " + type + "Array _" + names[i] + ";");
                }
                else
                {
                    stringBuilder.AppendLine("        public " + type + " " + names[i] + ";");
                }

                stringBuilder.Append("\n");
            }
            stringBuilder.AppendLine("        public static List<" + className + "> LoadBytes()");
            stringBuilder.AppendLine("        {");
            stringBuilder.AppendLine("            string bytesPath = \"" + BytesDataPath + "/" + className + ".bytes\";");
            stringBuilder.AppendLine("            if (!File.Exists(bytesPath))");
            stringBuilder.AppendLine("                return null;");
            stringBuilder.AppendLine("            using (FileStream stream = new FileStream(bytesPath, FileMode.Open))");
            stringBuilder.AppendLine("            {");
            stringBuilder.AppendLine("                BinaryFormatter binaryFormatter = new BinaryFormatter();");
            stringBuilder.AppendLine("                all" + className + " table = binaryFormatter.Deserialize(stream) as all" + className + ";");
            stringBuilder.AppendLine("                return table." + className + "s;");
            stringBuilder.AppendLine("            }");
            stringBuilder.AppendLine("        }");
            stringBuilder.AppendLine("    }");
            stringBuilder.Append("\n");
            stringBuilder.AppendLine("    [Serializable]");
            stringBuilder.AppendLine("    public class " + AllCsHead + className);
            stringBuilder.AppendLine("    {");
            stringBuilder.AppendLine("        public List<" + className + "> " + className + "s;");
            stringBuilder.AppendLine("    }");
            stringBuilder.AppendLine("}");

            string csPath = CsClassPath + "/" + className + ".cs";
            if (File.Exists(csPath))
            {
                File.Delete(csPath);
            }
            using (StreamWriter sw = new StreamWriter(csPath))
            {
                sw.Write(stringBuilder);
                Debug.Log("生成:" + csPath);
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError("写入CS失败:" + e.Message);
            throw;
        }
    }

    static void WriteXml(string className, string[] names, string[] types, List<string[]> datasList)
    {
        try
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
            stringBuilder.AppendLine("<" + AllCsHead + className + ">");
            stringBuilder.AppendLine("<" + className + "s>");
            for (int d = 0; d < datasList.Count; d++)
            {
                stringBuilder.Append("\t<" + className + " ");
                //单行数据
                string[] datas = datasList[d];
                //填充属性节点
                for (int c = 0; c < datas.Length; c++)
                {
                    string type = types[c];
                    if (!type.Contains("[]"))
                    {
                        string name = names[c];
                        string value = datas[c];
                        stringBuilder.Append(name + "=\"" + value + "\"" + (c == datas.Length - 1 ? "" : " "));
                    }
                }
                stringBuilder.Append(">\n");
                //填充子元素节点(数组类型字段)
                for (int c = 0; c < datas.Length; c++)
                {
                    string type = types[c];
                    if (type.Contains("[]"))
                    {
                        string name = names[c];
                        string value = datas[c];
                        string[] values = value.Split(ArrayTypeSplitChar);
                        stringBuilder.AppendLine("\t\t<" + name + ">");
                        for (int v = 0; v < values.Length; v++)
                        {
                            stringBuilder.AppendLine("\t\t\t<item>" + values[v] + "</item>");
                        }
                        stringBuilder.AppendLine("\t\t</" + name + ">");
                    }
                }
                stringBuilder.AppendLine("\t</" + className + ">");
            }
            stringBuilder.AppendLine("</" + className + "s>");
            stringBuilder.AppendLine("</" + AllCsHead + className + ">");

            string xmlPath = XmlDataPath + "/" + className + ".xml";
            if (File.Exists(xmlPath))
            {
                File.Delete(xmlPath);
            }
            using (StreamWriter sw = new StreamWriter(xmlPath))
            {
                sw.Write(stringBuilder);
                Debug.Log("生成文件:" + xmlPath);
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError("写入Xml失败:" + e.Message);
        }
    }

    static void Excel2CsOrXml(bool isCs)
    {
        string[] excelPaths = Directory.GetFiles(ExcelDataPath, "*.xlsx");
        for (int e = 0; e < excelPaths.Length; e++)
        {
            //0.读Excel
            string className;//类型名
            string[] names;//字段名
            string[] types;//字段类型
            string[] descs;//字段描述
            List<string[]> datasList;//数据

            try
            {
                string excelPath = excelPaths[e];//excel路径  
                className = Path.GetFileNameWithoutExtension(excelPath);
                FileStream fileStream = File.Open(excelPath, FileMode.Open, FileAccess.Read);
                IExcelDataReader excelDataReader = ExcelReaderFactory.CreateOpenXmlReader(fileStream);
                // 表格数据全部读取到result里
                DataSet result = excelDataReader.AsDataSet();
                // 获取表格列数
                int columns = result.Tables[0].Columns.Count;
                // 获取表格行数
                int rows = result.Tables[0].Rows.Count;
                // 根据行列依次读取表格中的每个数据
                names = new string[columns];
                types = new string[columns];
                descs = new string[columns];
                datasList = new List<string[]>();
                for (int r = 0; r < rows; r++)
                {
                    string[] curRowData = new string[columns];
                    for (int c = 0; c < columns; c++)
                    {
                        //解析:获取第一个表格中指定行指定列的数据
                        string value = result.Tables[0].Rows[r][c].ToString();

                        //清除前两行的变量名、变量类型 首尾空格
                        if (r < 2)
                        {
                            value = value.TrimStart(' ').TrimEnd(' ');
                        }

                        curRowData[c] = value;
                    }
                    //解析:第一行类变量名
                    if (r == 0)
                    {
                        names = curRowData;
                    }//解析:第二行类变量类型
                    else if (r == 1)
                    {
                        types = curRowData;
                    }//解析:第三行类变量描述
                    else if (r == 2)
                    {
                        descs = curRowData;
                    }//解析:第三行开始是数据
                    else
                    {
                        datasList.Add(curRowData);
                    }
                }
            }
            catch (System.Exception exc)
            {
                Debug.LogError("请关闭Excel:" + exc.Message);
                return;
            }

            if (isCs)
            {
                //写Cs
                WriteCs(FirstCharacterUppercase(className), names, types, descs);
            }
            else
            {
                //写Xml
                WriteXml(FirstCharacterUppercase(className), names, types, datasList);
            }
        }

        AssetDatabase.Refresh();
    }

    static string FirstCharacterUppercase(string s)
    {
        char[] a = s.ToCharArray();
        a[0] = char.ToUpper(a[0]);
        return new string(a);
    }

    static void WriteBytes()
    {
        string csAssemblyPath = Application.dataPath + "/../Library/ScriptAssemblies/Assembly-CSharp.dll";
        Assembly assembly = Assembly.LoadFile(csAssemblyPath);
        if (assembly != null)
        {
            Type[] types = assembly.GetTypes();
            for (int i = 0; i < types.Length; i++)
            {
                Type type = types[i];
                if (type.Namespace == "Table" && type.Name.Contains(AllCsHead))
                {
                    string className = type.Name.Replace(AllCsHead, "");

                    //读取xml数据
                    string xmlPath = XmlDataPath + "/" + className + ".xml";
                    if (!File.Exists(xmlPath))
                    {
                        Debug.LogError("Xml文件读取失败:" + xmlPath);
                        continue;
                    }
                    object table;
                    using (Stream reader = new FileStream(xmlPath, FileMode.Open))
                    {
                        //读取xml实例化table: all+classname
                        //object table = assembly.CreateInstance("Table." + type.Name);
                        XmlSerializer xmlSerializer = new XmlSerializer(type);
                        table = xmlSerializer.Deserialize(reader);
                    }
                    //obj序列化二进制
                    string bytesPath = BytesDataPath + "/" + className + ".bytes";
                    if (File.Exists(bytesPath))
                    {
                        File.Delete(bytesPath);
                    }
                    using (FileStream fileStream = new FileStream(bytesPath, FileMode.Create))
                    {
                        BinaryFormatter binaryFormatter = new BinaryFormatter();
                        binaryFormatter.Serialize(fileStream, table);
                        Debug.Log("生成:" + bytesPath);
                    }

                    if (IsDeleteXmlInFinish)
                    {
                        File.Delete(xmlPath);
                        Debug.Log("删除:" + bytesPath);
                    }
                }
            }
        }

        if (IsDeleteXmlInFinish)
        {
            Directory.Delete(XmlDataPath);
            Debug.Log("删除:" + XmlDataPath);
        }
    }
}

优点

  • 自动生成脚本
  • 一行代码调用
  • 什么时候使用什么时候读表,不会提前读表占用内存

GitCode地址

可移植读表功能

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

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

相关文章

【算法思维】-- 贪心算法

OJ须知&#xff1a; 一般而言&#xff0c;OJ在1s内能接受的算法时间复杂度&#xff1a;10e8 ~ 10e9之间&#xff08;中值5*10e8&#xff09;。在竞赛中&#xff0c;一般认为计算机1秒能执行 5*10e8 次计算。 时间复杂度取值范围o(log2n)大的离谱O(n)10e8O(nlog(n))10e6O(nsqrt(…

LinuxC编程——标准IO

目录 标准I/O一、概念二、特点⭐⭐⭐三、缓冲区⭐⭐⭐3.1 全缓冲3.1 行缓冲3.3 不缓冲 四、函数接口⭐⭐⭐⭐4.1 打开4.1.1 fopen4.1.2 freopen4.1.2 容错机制perror 4.2 关闭4.2.1 fclose4.3 读写操作4.3.1 字符I/O4.3.2 行I/O4.3.3 块I/O 4.4 定位操作4.5 文件结束和错误 脑图…

Redis高级数据结构之HyperLogLog

HyperLogLog的介绍 这并不是一种全新的数据结构、实际类型是一种字符串类型。通过一种基数&#xff08;不重复的元素数量就是基数&#xff09;算法&#xff0c;便可以使用很小的内存空间完成独立总数的统计。数据集可以是IP、Email、ID等官方给出的统计误差是0.81%&#xff0c…

python文本注释数学表达式设置|python绘图中的数学表达式设置

本篇文章将介绍如何在Matplotlib中设置文本、注释和数学表达式&#xff0c;以便更好地呈现数据&#xff0c;提高可视化效果。 文章目录 一、Matplotlib中的文本设置1.1 纯文本设置1.2 含箭头的文本设置 二、Matplotlib中的数学表达式设置三、Matplotlib中的字体设置 一、Matplo…

Vue项目中通过插件pxtorem实现大屏响应式

一、原理 rem单位代表的是根节点的font-size大小&#xff0c;所以当我们在页面上使用rem去替代px的时候&#xff0c;就可以通过修改根节点font-size的值&#xff0c;动态地让页面上的元素根据不同浏览器宽高下去实现变化。 二、工具 1.postcss-pxtorem 作用&#xff1a;在编…

Spring Boot Application.properties和yaml配置文件

文章目录 一、全局配置文件概述二、Application.properties配置文件&#xff08;一&#xff09;创建Spring Boot的Web项目PropertiesDemo&#xff08;二&#xff09;在应用属性文件里添加相关配置1、配置服务器端口号和web虚拟路径2、对象类型的配置与使用&#xff08;1&#x…

微应用如何实现自动更新提示

首先, 先讲一下本次文章所讲的场景, 经过调研, 公司内部使用后台, 当有需求功能迭代的时候, 通常使用者会没有感知, 使用者只会在浏览器内一直打开这个页面, 当需要使用的时候, 再切换这个tab来使用. 这就导致使用者一直不知道系统更新了, 一直没有访问最新的页面(由于最新页面…

日志框架——Log4j2

日志框架——Log4j2 日志框架Log4j21. 概述2. Log4j2主要由几个重要的组件构成:3.项目中使用3.1 引入相关依赖pom.xml3.2 加入日志配置文件src/main/resources/log4j2.xml3.3 测试 日志框架Log4j2 1. 概述 Apache Log4j2是一个开源的日志记录组件&#xff0c;使用非常的广泛。…

【Protobuf速成指南】什么是Protobuf?

文章目录 一、序列化和反序列化1.1 概念1.2 场景1.3 如何序列化 二、Protobuf介绍1. 自身特点2.使用特点 一、序列化和反序列化 1.1 概念 &#x1f3af;[总结]: 序列化&#xff1a;把对象转换为字节序列的过程称为对象的序列化。反序列化&#xff1a;把字节序列恢复为对象的过…

MySQL数据库 8.DML操作

目录 ​编辑 &#x1f914;前言&#xff1a; &#x1f914;DML介绍&#xff1a; &#x1f914;语法详情&#xff1a; &#x1f600;1.插入数据&#xff1a; 特点&#xff1a; 1.给指定字段添加数据&#xff1a; 代码示例: 运行结果&#xff1a; 2.给所有的字段添加数据&…

好的用户体验和性能:现代前端的双赢之路

部分数据来源&#xff1a;ChatGPT 引言 随着 Web 应用程序的复杂度和重要性逐渐上升&#xff0c;前端开发人员已经开始更加注重应用程序的可用性和性能。在这个快速变化的时代&#xff0c;前端开发是日益增长的一个领域。 在当前的前端领域&#xff0c;用户体验和性能是前端开…

解决在谷歌浏览器下载时文件名包含逗号导致页面显示网页不可用问题

项目场景&#xff1a; 自己开发的文件服务项目在使用时测试反馈在下载文件时&#xff0c;文件名包含逗号时下载失败&#xff0c;无法跳转到下载链接页面。 项目使用springboot开发&#xff0c;文件的上传基于SpringMVC的表单文件上传。但是下载时由于需要下载原文件名&#xf…

【IC设计】基于Verilog的8层矩阵乘法设计

文章目录 项目要求基本要求截断要求低位截断高位饱和 参考结果 项目实现实现思路实现代码matrix_multiplier_16.vtb_mm_mlp.v VCS&Verdi综合前仿真dc综合VCS&Verdi综合后仿真不足之处 项目要求 基本要求 输入有9个矩阵&#xff0c;权重矩阵有8个&#xff0c;分别是We…

win11安装open-ssh server

帮助链接&#xff1a; 安装 OpenSSH | Microsoft Learn step1: 本机管理模式的power shell下查询安装状态 Get-WindowsCapability -Online | Where-Object Name -like OpenSSH* Name : OpenSSH.Client~~~~0.0.1.0 State : InstalledName : OpenSSH.Server~~~~0.0.1.0 Stat…

Kafka生产者与消费者api示例

生产者api示例 一个正常的生产逻辑需要具备以下几个步骤 配置生产者参数及创建相应的生产者实例 构建待发送的消息 发送消息 关闭生产者实例 采用默认分区方式将消息散列的发送到各个分区当中 package com.doitedu;import org.apache.kafka.clients.producer.KafkaProduce…

【人工智能】— 线性分类器、感知机、损失函数的选取、最小二乘法分类、模型复杂性和过度拟合、规范化

【人工智能】— 感知机、线性分类器、感知机、感知机、最小二乘法分类、模型复杂性和过度拟合、规范化 Linear predictions 线性预测分类线性分类器感知机感知机学习策略损失函数的选取距离的计算 最小二乘法分类求解最小二乘分类矩阵解法一般线性分类模型复杂性和过度拟合训练…

重估端到端原则

评价技术迭代的旧的定势眼光来自于该技术诞生时。 1970/80/90 年代&#xff0c;相比传输带宽技术&#xff0c;处理器更强。网络协议倾向于字段多&#xff0c;字段小且紧凑&#xff0c;尽可能减少传输量&#xff0c;用 “算法技巧” 等价&#xff0c;如果 TCP 序列号 48 位&…

【iOS】消息传递和消息转发机制

消息传递机制 在OC语言中&#xff0c;调用对象的方法被叫做消息传递。消息有名称和选择子(selector)&#xff0c;可以接受参数&#xff0c;还可能有返回值。 在Objective-C中&#xff0c;如果向某对象传递消息&#xff0c;那就会使用动态绑定机制来决定需要调用的方法。在底层…

C++进阶 —— 范围for(C++11新特性)

目录 一&#xff0c;范围for介绍 二&#xff0c;范围for注意事项 一&#xff0c;范围for介绍 范围for&#xff08;range-based for loop&#xff09;是C11新引入的特性&#xff0c;可遍历各种序列结构的容器&#xff08;如数组、vector、list等&#xff09;&#xff1b;每次循…

【QT】Qt ApplicationManager Compositor源码分析

Qt ApplicationManager的Compositor功能分析 根据Qt ApplicationManager官网介绍&#xff0c;它基于Wayland协议实现了Compositor功能。下述为官网介绍。实际上&#xff0c;QtApplicationManager是使用了QtWayland模块来实现Compositor的。Wayland是一套旨在替代XWindow的 Com…