excel2json是一款将Excel表格文件快速生成json和C#数据类的高效插件,详情了解如下:

https://neil3d.github.io/coding/excel2json.html

该插件有两种模式,分别是命令行和图像界面;当然了,为了更方便愉快的进行大规模转换,可以写两个批处理文件来执行:

Single文件表示执行单个选中文件,AutoAll表示执行该路径下所有xlsx文件;输出文件夹的位置为output,如果该目录下无output文件夹,则自动创建:

Single.bat详情如下:

 @SET OUTPUT_FOLDER=.\output
@SET EXE=.\tool\excel2json.exe if not exist %OUTPUT_FOLDER% md %OUTPUT_FOLDER% @echo off
set path=%
echo 源文件路径%path%
set name=%~n1
echo 源文件名%name%
set outputpath=%OUTPUT_FOLDER%\%name%
echo 输出文件路径%outputpath% @CALL %EXE% --excel %path% --json %outputpath%.json --header --csharp %outputpath%.cs -a pause

前两行为参数设置,分别为输出文件夹路径和可执行文件路径,一个%表示参数,后面使用该参数作为变量时格式为[%参数%]。[.\]代表相对路径

第四行,如果不存在该路径文件夹则自动创建,注意如果没有这一行也没有对应参数所指示的路径,这时并不会自动创建路径而是会直接报错

第七行,得到当前选中的第一个文件路径作为参数

第九行,得到当前选中的第一个文件的文件名(不包含后缀)

类似的还有:

%~d1\   得到当前选中的第一个文件所在磁盘符

%~dp1  得到当前选中的第一个文件路径位置(不包含文件名和文件后缀名)

%~nx1 得到当前选中的第一个文件的文件名和后缀

这里主要是为了保持输出文件的名称与选择的文件名称一致,所以最终的输出路径为设置的输出路径位置+源文件名

最后调用@CALL 执行参数对应路径下的exe文件,根据excel2json提供的命令行参数设置启动参数。

AutoAll.bat详情如下:

 @SET EXCEL_FOLDER=.\
@SET OUTPUT_FOLDER=.\output
@SET EXE=.\tool\excel2json.exe @ECHO Converting excel files in folder %EXCEL_FOLDER% ...
if not exist %OUTPUT_FOLDER% md %OUTPUT_FOLDER% for /f "delims=" %%i in ('dir /b /a-d /s %EXCEL_FOLDER%\*.xlsx') do (
@echo processing %%~nxi
@CALL %EXE% --excel %EXCEL_FOLDER%\%%~nxi --json %OUTPUT_FOLDER%\%%~ni.json --header --csharp %OUTPUT_FOLDER%\%%~ni.cs -a
)
pause

上面这个批处理文件在帮助页面中有实例,最主要是做了一个路径内的文件查询和批量执行:

dir /b /a-d /s  从指定路径遍历搜索文件,路径参数即为当前路径下的所有.xlsx文件,当然了,也可以动态修改前面的excel所在文件夹参数配置

%%~nxi与%%~ni 和上面的类似只不过不是1而是循环体中的变量i,表示对应数目索引的文件

需要注意的是,在cmd模式下的循环变量是一个百分号加循环标识符(即%i)而在批处理文件中需要两个百分号才行(%%i)

下面提供已经写好批处理的文件下载链接:

https://files.cnblogs.com/files/koshio0219/excel2json.zip

这里的批处理统一将Execl导出为数组类型,方便在Unity中进一步反序列化,如果需要字典类型,可以继续修改或添加帮助中指定的参数,也可以直接利用图形界面分别导出

之所以默认导出数组类型,因为Unity默认的JsonUtility解析字典类型几乎是不可能,即使强行可以,那也是用的两个List做对应关系,

跟真正的字典类型导出的Json文件格式区别很大,直接解析出来就是个空文件。当然了,如果只是用于数据保存和读写是这么做是完全可以的,

只要读和写都是用的同一个序列化和反序列化的方式即可。但excel2json本身也并不是专门为了Unity的序列化而做的;

查看该工程的源代码就可以知道,该工程用的序列化方式为Newtonsoft.Json,如果实在需要用字典类型来解析,可以直接导入该Dll使用;

下面分别进行数组型Json与字典型Json的反序列化讨论:

1.数组型Json(或List型)

比如下面这段测试Json和C#文件:(通过excel2json导出)

  [
{
"ID": "4l523",
"Hp": ,
"Atk": 6.3,
"Def": ,
"State": ""
},
{
"ID": "p6",
"Hp": ,
"Atk": ,
"Def": 2.3,
"State": ""
},
{
"ID": 0.3,
"Hp": 0.2,
"Atk": "2.3,7",
"Def": ,
"State": ""
}
]
 [System.Serializable]
public class Buff
{
public string ID; // 编号
public int Hp; // 血量
public float Atk; // 攻击
public float Def; // 防御
public BuffData State; // 状态
}

为了进行测试,我在Excel表格中故意填错一些与当前类型不匹配的数据,例如第三组中的ID,Hp,Atk,Def都设置得与当前的数据类型不同,且Atk一个表格中填了两个数字;

Unity解析数组(或List)Json文件也不能直接反序列化,例如直接写为:

var data = JsonUtility.FromJson<Buff[]>(json.text);

只会得到一个空的数据结构。

这里需要一个额外的序列化转换:

 using UnityEngine;

 public class JsonHelper
{
public static T[] GetJsonArray<T>(string json)
{
string newJson = "{ \"array\": " + json + "}";
Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(newJson);
return wrapper.array;
} [System.Serializable]
private class Wrapper<T>
{
public T[] array;
}
}

需要注意的是,如果以该方式反序列化数组,之前导出的Json文件不能包含文件名,在上面的脚本中统一将文件名添加为array。

newJson的文件名称必须与Wrapper类中的泛型数组T[]的名字保持一致,才能反序列化出指定数据。

如果不利用泛型的话,需要每一个文件单独再写一个类来进行反序列化,同样的数组的标识符必须与Json中的Array文件名称保持一致。

为了更方便的通过ID来读取数据,也可以将得到的数组再重新写入一个字典中,通过反射在获取ID的值作为键,前提是规定每一个Json文件中必须有ID这一字段:

 public class JsonDatas<T>
{
public Dictionary<string, T> Dict = new Dictionary<string, T>();
public static JsonDatas<T> FromJson(string json)
{
var re = new JsonDatas<T>();
var datas = JsonHelper.GetJsonArray<T>(json);
foreach(var data in datas)
{
var info = data.GetType().GetField("ID");
var idstr = info.GetValue(data).ToString();
re.Dict.Add(idstr, data);
}
return re;
} public T Get(string ID)
{
return Dict[ID];
}
}

这里反射取字段值得时候遇到了一个坑,特意记录一下:

Type.GetField(string name) 这个是取字段的值,取不了属性

Type.GetProperty(string name) 这个是取属性的值,取不了字段

这两个取出来的内容是不一样的,请注意区分,不然半天也查不出错误出在哪里(说的就是我本人)

调试后的结果如下,能够成功解析出Json了:

这里特意来看看第三组数据为什么没有报错 ,神奇的是,JsonUtility竟然自动帮你转化为了对应的类型:

ID  0.3被转为了“0.300000”;Hp 0.2 变为了0;更震惊的是,Atk竟然也没有报错,而是成功解析出了逗号前面的数字,emm有点迷。

个人猜想是JsonUtility先尝试将错误的数据类型转为正确类型,如果无法转换,则从头开始读,读取到该类型下无法识别的字符就自动终止。(只是随便猜猜不用太当真)

2.字典型Json

如果非要导出字典型Json来反序列化,那就不能再用Unity自带的JsonUtility了,而是最好导入和序列化时用的是一样的Newtonsoft.Json

下面提供与Unity适配的Newtonsoft.Json包JsonNet.9.0.1.unitypackage下载地址:

https://files.cnblogs.com/files/koshio0219/JsonNet.9.0.1.zip

如果是反序列化单个不带任何签名的字典,只用一句话就可以了,不需要建立任何新类:

var data = JsonConvert.DeserializeObject<Dictionary<string, Buff>>(json.text);

试比较带签名和不带签名的Json:

 {
"Buff": {
"4l523": {
"ID": "4l523",
"Hp": ,
"Atk": 6.3,
"Def": ,
"State": ""
},
"p6": {
"ID": "p6",
"Hp": ,
"Atk": ,
"Def": 2.3,
"State": ""
},
"0.3": {
"ID": 0.3,
"Hp": ,
"Atk": ,
"Def": ,
"State": ""
}
}
}

 {
"4l523": {
"ID": "4l523",
"Hp": ,
"Atk": 6.3,
"Def": ,
"State": ""
},
"p6": {
"ID": "p6",
"Hp": ,
"Atk": ,
"Def": 2.3,
"State": ""
},
"0.3": {
"ID": 0.3,
"Hp": ,
"Atk": ,
"Def": ,
"State": ""
}
}

只要带有签名或者存在多个表单文件在同一个Json中,就只能重新建立新类并解析该新类了,新类中的变量顺序和标识符都必须与Json文件中的顺序与签名保持一致:

     public class Buffs
{
//变量名称Buff必须与Json中的签名Buff一样
public Dictionary<string, Buff> Buff = new Dictionary<string, Buff>();
}

叫人失落的是,Newtonsoft.Json并不会良心的帮你把错误的数据自动转换,而是直接给你抛出一个错误,这一点和JsonUtility不同。

补充:

一个有趣的实验——强行用Unity中的字典序列化方式来序列化Json文件会是怎样?

开始之前,我们要明白的是,Unity默认根本就没有给出任何字典序列化的方式,它只能蠢蠢的序列化List或者Array,但这并不能阻止我们,我们可以讨巧的利用ISerializationCallbackReceiver接口来实现一个伪序列化:

 using UnityEngine;
using System;
using System.Collections.Generic; // Dictionary<TKey, TValue>
[Serializable]
public class Serialization<TKey, TValue> : ISerializationCallbackReceiver
{
[SerializeField]
List<TKey> keys;
[SerializeField]
List<TValue> values; Dictionary<TKey, TValue> target;
public Dictionary<TKey, TValue> ToDictionary() { return target; } public Serialization(Dictionary<TKey, TValue> target)
{
this.target = target;
} public void OnBeforeSerialize()
{
keys = new List<TKey>(target.Keys);
values = new List<TValue>(target.Values);
} public void OnAfterDeserialize()
{
var count = Math.Min(keys.Count, values.Count);
target = new Dictionary<TKey, TValue>(count);
for (var i = ; i < count; ++i)
{
target.Add(keys[i], values[i]);
}
}
}

把之前反序列化出的数据再用该伪序列化方式来序列化为Json文件:

         var SerializedBuff= new Serialization<string, Buff>(new Dictionary<string, Buff>());
var data = JsonConvert.DeserializeObject<Buffs>(json.text);
foreach(var item in data.Buff)
{
SerializedBuff.ToDictionary().Add(item.Key, item.Value);
}
var jsont = JsonUtility.ToJson(SerializedBuff);
Debug.Log(jsont);

实验结果如下:

 {
"keys":[
"4l523",
"p6",
"0.3"],
"values":[
{
"ID":"4l523",
"Hp":,
"Atk":6.300000190734863,
"Def":7.0,
"State":{
}
},
{
"ID":"p6",
"Hp":,
"Atk":8.0,
"Def":2.299999952316284,
"State":{
}
},
{
"ID":"0.3",
"Hp":,
"Atk":7.0,
"Def":9.0,
"State":{
}
}]
}

我们发现它根本不是一个字典类型,序列化之后的结构和原来的结构相差非常大,实际上是Keys在一起Values在一起,只是它们的索引是相互对应的。

Unity 基于excel2json批处理读取Excel表并反序列化的更多相关文章

  1. Python+Selenium进行UI自动化测试项目中,常用的小技巧1:读取excel表,转化成字典(dict)输出

    从今天开始我将会把在项目中遇到的问题,以及常用的一些技巧来分享出来,以此来促进自己的学习和提升自己:更加方便我以后的查阅. 现在要说的是:用Python来读取excel表的数据,返回字典(dict), ...

  2. Aspose.cells 读取Excel表中的图片问题

    一.说明 本文主要是讲解,怎么使用aspose.cells读取Excel表中的图片,并把图片转换成流或是image对象. 二.开发环境说明 开发工具vs2012,c#语言, 三.Aspose.cell ...

  3. Jmeter读取excel表中用例数据实现接口压测

    传统的接口测试,都是在接口中手动输入不同用例准备的多种场景参数数据,一遍一遍的输入来执行多个不同的用例,但是现在利用excel表格准备各种类型的数据,使用Jmeter中Jmeter CSV Data ...

  4. Python xlrd模块读取Excel表中的数据

    1.xlrd库的安装 直接使用pip工具进行安装(当然也可以使用pycharmIDE进行安装,这里就不详述了) pip install xlrd 2.xlrd模块的一些常用命令 ①打开excel文件并 ...

  5. C#读取Excel表中的数据时,为何有些行的字段内容读取不到

    转载:http://bbs.csdn.net/topics/360220285 1.当某列数据中含有混合类型时,在.NET中使用Microsoft.Jet.OLEDB.4.0来读取Excel文件造成数 ...

  6. Java读取excel表,getPhysicalNumberOfCells()和getLastCellNum区别

    excel表存入数据库,发现有时报数组下标越界异常.调试发现用了 getPhysicalNumberOfCells(),这个是用来获取不为空的的列个数. getLastCellNum是获取最后一个不为 ...

  7. python读取excel表

    from xlrd import open_workbookimport re #创建一个用于读取sheet的生成器,依次生成每行数据,row_count 用于指定读取多少行, col_count 指 ...

  8. 基于注解的读取excel的工具包

    easyexcel-wraper easyexcel-wraper是什么? 一个方便读取excel内容,且可以使用注解进行内容验证的包装工具 easyexcel-wraper有哪些功能? 在easye ...

  9. unity 读取excel表 生成asset资源文件

    做unity 项目也有一段时间了,从unity项目开发和学习中也遇到了很多坑,并且也从中学习到了很多曾经未接触的领域.项目中的很多功能模块,从今天开始把自己的思路和代码奉上给学渣们作为一份学习的资料. ...

随机推荐

  1. Oracle 导入数据库dmp文件

    场景:windows2008 R2系统 ,往新安装的oracle11g数据库导入同事给的dmp文件到指定的新建的用户. 1.创建表空间 在导入dmp文件之前,先打开查看dmp文件的表空间名称(tabl ...

  2. 学习python的基本了解

    1) 使用python打印信息,分别打印你的名字.年龄.爱好# print('wang,23,shopping')# 2)使用变量,分别打印你的名字.年龄.爱好# name='wang'# age=2 ...

  3. Java工具类—包装类

    Java工具类--包装类 我们都知道,JDK 其实给我们提供了很多很多 Java 开发者已经写好的现成的类,他们其实都可以理解成工具类,比如我们常见的集合类,日期相关的类,数学相关的类等等,有了这些工 ...

  4. 深入理解JVM(③)虚拟机的类加载过程

    前言 上一篇我们介绍到一个类的生命周期大概分7个阶段:加载.验证.准备.解析.初始化.使用.卸载.并且也介绍了类的加载时机,下面我们将介绍一下虚拟机中类的加载的全过程.主要是类生命周期的,加载.验证. ...

  5. vue全家桶(4.2)

    5.2.使用vuex重构上面代码 Vuex是什么?官方定义:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测 ...

  6. 手把手教你把web应用丢到服务器上(单页应用+ 服务端渲染)

    前两篇文章中,我分别介绍了框架的搭建利用vue-cli + vant搭建一个移动端开发模板,并且把项目中axios请求和vuex的用法做了简要的介绍如何在项目里管理好axios请求与vuex.在这两篇 ...

  7. 控制shell终端提示符格式和颜色

    字体颜色值 (ASCII) 背景颜色值 (ASCII) 显示颜色 30 40 黑色 31 41 红色 32 42 绿色 33 43 黄色 34 44 蓝色 35 45 紫红色 36 46 青蓝色 37 ...

  8. 图形处理:给 Canvas 文本填充线性渐变

    作者:凹凸曼 - Barrior 在 Canvas 中对文本填充水平或垂直的线性渐变可以轻易实现,而带角度的渐变就复杂很多:就好像下面这样,假设文本矩形宽为 W, 高为 H, 左上角坐标为 X, Y. ...

  9. day22 常用模块(上)

    一.时间模块 1 time模块 获取时间的三种格式: 第一种:time.time() 时间戳(timestamp):从1970年到现在的秒数 #应用场景:计算时间差 可以对时间加减,返回值为浮点型 p ...

  10. eShopOnContainers 知多少[11]:服务间通信之gRPC

    引言 最近翻看最新3.0 eShopOncontainers源码,发现其在架构选型中补充了 gRPC 进行服务间通信.那就索性也写一篇,作为系列的补充. gRPC 老规矩,先来理一下gRPC的基本概念 ...