测试修改
This commit is contained in:
@@ -1,298 +1,320 @@
|
|||||||
# ExcelTool(Unity打表工具)
|
# ExcelTool(Unity打表工具)
|
||||||
|
|
||||||
通用CSV/Excel打表工具
|
通用CSV/Excel打表工具
|
||||||
#### 前言
|
|
||||||
目前项目中用的csv转json工具,会带来严重的gc性能问题,例如启动加载慢,影响帧率等问题,转成的json数据,我们需要手动写对应的解析模板代码,所以针对以上问题,本通用打表工具应运而生,用二进制数据替代json数据会比较好的解决性能问题,而且能够自动生成对应的模板代码,节省了写重复代码的时间,而且二进制数据比json读取速度更快,文件大小更小。
|
#### 前言
|
||||||
|
|
||||||
#### 说明
|
目前项目中用的csv转json工具,会带来严重的gc性能问题,例如启动加载慢,影响帧率等问题,转成的json数据,我们需要手动写对应的解析模板代码,所以针对以上问题,本通用打表工具应运而生,用二进制数据替代json数据会比较好的解决性能问题,而且能够自动生成对应的模板代码,节省了写重复代码的时间,而且二进制数据比json读取速度更快,文件大小更小。
|
||||||
因为csv有默认的逗号,这跟表中内容配置逗号会有冲突,不利于解析,所有产生了加强版的ExcelTool,读取路径下的csv和excel表格,如果是csv的这先转换成xlsx的excel,然后统一对excel进行数据读取解析操作,生成完之后再把csv生成的excel删掉,确保目录保持原样,所以ExcelTool是CsvTool的升级版
|
|
||||||
|
#### 说明
|
||||||
#### 功能
|
|
||||||
* 支持csv和Excel的打表
|
因为csv有默认的逗号,这跟表中内容配置逗号会有冲突,不利于解析,所有产生了加强版的ExcelTool,读取路径下的csv和excel表格,如果是csv的这先转换成xlsx的excel,然后统一对excel进行数据读取解析操作,生成完之后再把csv生成的excel删掉,确保目录保持原样,所以ExcelTool是CsvTool的升级版
|
||||||
* 生成对应的数据模板代码
|
|
||||||
* 支持生成模板代码字段注释
|
#### 功能
|
||||||
* 生成二进制文件
|
|
||||||
* 自动将文件拷贝到对应的工程目录
|
* 支持csv和Excel的打表
|
||||||
* 二进制数据读取
|
* 生成对应的数据模板代码
|
||||||
* 字段不配置会使用默认数值
|
* 支持生成模板代码字段注释
|
||||||
|
* 生成二进制文件
|
||||||
#### 目前支持的字段
|
* 自动将文件拷贝到对应的工程目录
|
||||||
* 常规的字段,例如int,float,string,bool,long,list,intlist,longlist,floatlist,boollist,List<T> 大小写不限
|
* 二进制数据读取
|
||||||
* 支持自定义字段 vector,例如[1,2,3]
|
* 字段不配置会使用默认数值
|
||||||
* 支持自定义字段 list,其实是vector数组,例如[[1,2,3],[2,3,4],[4,5,6]]
|
|
||||||
|
#### 目前支持的字段
|
||||||
#### 效果
|
|
||||||

|
* 常规的字段,例如int,float,string,bool,long,list,intlist,longlist,floatlist,boollist,List<T> 大小写不限
|
||||||
|
* 支持自定义字段 vector,例如[1,2,3]
|
||||||

|
* 支持自定义字段 list,其实是vector数组,例如[[1,2,3],[2,3,4],[4,5,6]]
|
||||||
相比较json,二进制文件大小只有其1/4
|
|
||||||
|
#### 效果
|
||||||
##### 自动生成的模板代码
|
|
||||||
```
|

|
||||||
/*
|
|
||||||
* auto generated by tools(注意:千万不要手动修改本文件)
|

|
||||||
* avatarguideTest
|
相比较json,二进制文件大小只有其1/4
|
||||||
*/
|
|
||||||
using System;
|
##### 自动生成的模板代码
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
```
|
||||||
using System.Text;
|
/*
|
||||||
using System.Linq;
|
* auto generated by tools(注意:千万不要手动修改本文件)
|
||||||
|
* avatarguideTest
|
||||||
[Serializable]
|
*/
|
||||||
public class avatarguideTest : IBinarySerializable
|
using System;
|
||||||
{
|
using System.IO;
|
||||||
public int Id { get; set; }
|
using System.Collections.Generic;
|
||||||
public string gender { get; set; }
|
using System.Text;
|
||||||
public float age { get; set; }
|
using System.Linq;
|
||||||
public bool bValue { get; set; }
|
|
||||||
public List<float> vector { get; set; }
|
[Serializable]
|
||||||
public List<List<float>> Grid { get; set; }
|
public class avatarguideTest : IBinarySerializable
|
||||||
|
{
|
||||||
public void DeSerialize(BinaryReader reader)
|
public int Id { get; set; }
|
||||||
{
|
public string gender { get; set; }
|
||||||
Id = reader.ReadInt32();
|
public float age { get; set; }
|
||||||
gender = reader.ReadString();
|
public bool bValue { get; set; }
|
||||||
age = reader.ReadSingle();
|
public List<float> vector { get; set; }
|
||||||
bValue = reader.ReadBoolean();
|
public List<List<float>> Grid { get; set; }
|
||||||
var vectorCount = reader.ReadInt32();
|
|
||||||
if (vectorCount > 0)
|
public void DeSerialize(BinaryReader reader)
|
||||||
{
|
{
|
||||||
vector = new List<float>();
|
Id = reader.ReadInt32();
|
||||||
for (int i = 0; i < vectorCount; i++)
|
gender = reader.ReadString();
|
||||||
{
|
age = reader.ReadSingle();
|
||||||
vector.Add(reader.ReadSingle());
|
bValue = reader.ReadBoolean();
|
||||||
}
|
var vectorCount = reader.ReadInt32();
|
||||||
}
|
if (vectorCount > 0)
|
||||||
else
|
{
|
||||||
{
|
vector = new List<float>();
|
||||||
vector = null;
|
for (int i = 0; i < vectorCount; i++)
|
||||||
}
|
{
|
||||||
var GridCount = reader.ReadInt32();
|
vector.Add(reader.ReadSingle());
|
||||||
if (GridCount > 0)
|
}
|
||||||
{
|
}
|
||||||
Grid = new List<List<float>>();
|
else
|
||||||
for (int i = 0; i < GridCount; i++)
|
{
|
||||||
{
|
vector = null;
|
||||||
var tempList = new List<float>();
|
}
|
||||||
var tempListCount = reader.ReadInt32();
|
var GridCount = reader.ReadInt32();
|
||||||
for (int j = 0; j < tempListCount; j++)
|
if (GridCount > 0)
|
||||||
{
|
{
|
||||||
tempList.Add(reader.ReadSingle());
|
Grid = new List<List<float>>();
|
||||||
}
|
for (int i = 0; i < GridCount; i++)
|
||||||
Grid.Add(tempList);
|
{
|
||||||
}
|
var tempList = new List<float>();
|
||||||
}
|
var tempListCount = reader.ReadInt32();
|
||||||
else
|
for (int j = 0; j < tempListCount; j++)
|
||||||
{
|
{
|
||||||
Grid = null;
|
tempList.Add(reader.ReadSingle());
|
||||||
}
|
}
|
||||||
}
|
Grid.Add(tempList);
|
||||||
|
}
|
||||||
public void Serialize(BinaryWriter writer)
|
}
|
||||||
{
|
else
|
||||||
writer.Write(Id);
|
{
|
||||||
writer.Write(gender);
|
Grid = null;
|
||||||
writer.Write(age);
|
}
|
||||||
writer.Write(bValue);
|
}
|
||||||
if (vector == null || vector.Count == 0)
|
|
||||||
{
|
public void Serialize(BinaryWriter writer)
|
||||||
writer.Write(0);
|
{
|
||||||
}
|
writer.Write(Id);
|
||||||
else
|
writer.Write(gender);
|
||||||
{
|
writer.Write(age);
|
||||||
writer.Write(vector.Count);
|
writer.Write(bValue);
|
||||||
for (int i = 0; i < vector.Count; i++)
|
if (vector == null || vector.Count == 0)
|
||||||
{
|
{
|
||||||
writer.Write(vector[i]);
|
writer.Write(0);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
if (Grid == null || Grid.Count == 0)
|
{
|
||||||
{
|
writer.Write(vector.Count);
|
||||||
writer.Write(0);
|
for (int i = 0; i < vector.Count; i++)
|
||||||
}
|
{
|
||||||
else
|
writer.Write(vector[i]);
|
||||||
{
|
}
|
||||||
writer.Write(Grid.Count);
|
}
|
||||||
for (int i = 0; i < Grid.Count; i++)
|
if (Grid == null || Grid.Count == 0)
|
||||||
{
|
{
|
||||||
writer.Write(Grid[i].Count);
|
writer.Write(0);
|
||||||
for (int j = 0; j < Grid[i].Count; j++)
|
}
|
||||||
{
|
else
|
||||||
writer.Write(Grid[i][j]);
|
{
|
||||||
}
|
writer.Write(Grid.Count);
|
||||||
}
|
for (int i = 0; i < Grid.Count; i++)
|
||||||
}
|
{
|
||||||
}
|
writer.Write(Grid[i].Count);
|
||||||
public override string ToString()
|
for (int j = 0; j < Grid[i].Count; j++)
|
||||||
{
|
{
|
||||||
var str = $"Id:{Id} Gender:{gender} age:{age} bValue:{bValue} ";
|
writer.Write(Grid[i][j]);
|
||||||
if (vector != null)
|
}
|
||||||
{
|
}
|
||||||
str += $"vector:[{vector[0]},{vector[1]},{vector[2]}] ";
|
}
|
||||||
}
|
}
|
||||||
if (Grid != null)
|
public override string ToString()
|
||||||
{
|
{
|
||||||
str += "Grid:[";
|
var str = $"Id:{Id} Gender:{gender} age:{age} bValue:{bValue} ";
|
||||||
for (int i = 0; i < Grid.Count; i++)
|
if (vector != null)
|
||||||
{
|
{
|
||||||
str += $"[{Grid[i][0]},{Grid[i][1]},{Grid[i][2]}]";
|
str += $"vector:[{vector[0]},{vector[1]},{vector[2]}] ";
|
||||||
if (i < Grid.Count - 1)
|
}
|
||||||
str += ",";
|
if (Grid != null)
|
||||||
}
|
{
|
||||||
str += "]";
|
str += "Grid:[";
|
||||||
}
|
for (int i = 0; i < Grid.Count; i++)
|
||||||
return str;
|
{
|
||||||
}
|
str += $"[{Grid[i][0]},{Grid[i][1]},{Grid[i][2]}]";
|
||||||
}
|
if (i < Grid.Count - 1)
|
||||||
|
str += ",";
|
||||||
[Serializable]
|
}
|
||||||
public partial class avatarguideTestConfig : IBinarySerializable
|
str += "]";
|
||||||
{
|
}
|
||||||
public List<avatarguideTest> avatarguideTestInfos = new List<avatarguideTest>();
|
return str;
|
||||||
public void DeSerialize(BinaryReader reader)
|
}
|
||||||
{
|
}
|
||||||
int count = reader.ReadInt32();
|
|
||||||
for (int i = 0;i < count; i++)
|
[Serializable]
|
||||||
{
|
public partial class avatarguideTestConfig : IBinarySerializable
|
||||||
avatarguideTest tempData = new avatarguideTest();
|
{
|
||||||
tempData.DeSerialize(reader);
|
public List<avatarguideTest> avatarguideTestInfos = new List<avatarguideTest>();
|
||||||
avatarguideTestInfos.Add(tempData);
|
public void DeSerialize(BinaryReader reader)
|
||||||
}
|
{
|
||||||
}
|
int count = reader.ReadInt32();
|
||||||
|
for (int i = 0;i < count; i++)
|
||||||
public void Serialize(BinaryWriter writer)
|
{
|
||||||
{
|
avatarguideTest tempData = new avatarguideTest();
|
||||||
writer.Write(avatarguideTestInfos.Count);
|
tempData.DeSerialize(reader);
|
||||||
for (int i = 0; i < avatarguideTestInfos.Count; i++)
|
avatarguideTestInfos.Add(tempData);
|
||||||
{
|
}
|
||||||
avatarguideTestInfos[i].Serialize(writer);
|
}
|
||||||
}
|
|
||||||
}
|
public void Serialize(BinaryWriter writer)
|
||||||
|
{
|
||||||
public IEnumerable<avatarguideTest> QueryById(int id)
|
writer.Write(avatarguideTestInfos.Count);
|
||||||
{
|
for (int i = 0; i < avatarguideTestInfos.Count; i++)
|
||||||
var datas = from d in avatarguideTestInfos
|
{
|
||||||
where d.Id == id
|
avatarguideTestInfos[i].Serialize(writer);
|
||||||
select d;
|
}
|
||||||
return datas;
|
}
|
||||||
}
|
|
||||||
|
public IEnumerable<avatarguideTest> QueryById(int id)
|
||||||
public override string ToString()
|
{
|
||||||
{
|
var datas = from d in avatarguideTestInfos
|
||||||
StringBuilder sb = new StringBuilder();
|
where d.Id == id
|
||||||
for (int i = 0; i < avatarguideTestInfos.Count; i++)
|
select d;
|
||||||
{
|
return datas;
|
||||||
sb.Append($"{avatarguideTestInfos[i].ToString()}\n");
|
}
|
||||||
}
|
|
||||||
return sb.ToString();
|
public override string ToString()
|
||||||
}
|
{
|
||||||
}
|
StringBuilder sb = new StringBuilder();
|
||||||
```
|
for (int i = 0; i < avatarguideTestInfos.Count; i++)
|
||||||
|
{
|
||||||
#### 使用案例
|
sb.Append($"{avatarguideTestInfos[i].ToString()}\n");
|
||||||
##### 解析二进制文件
|
}
|
||||||
```
|
return sb.ToString();
|
||||||
IBinarySerializable newavList = new avatarguideTestList();
|
}
|
||||||
var readOK = FileManager.ReadBinaryDataFromFile(Path.Combine(path, "avatarguideTest.dat"), ref newavList);
|
}
|
||||||
if (readOK)
|
```
|
||||||
{
|
|
||||||
ConsoleHelper.WriteInfoLine(newavList.ToString());
|
#### 使用案例
|
||||||
}
|
|
||||||
else
|
##### 解析二进制文件
|
||||||
{
|
|
||||||
ConsoleHelper.WriteErrorLine("读取失败");
|
```
|
||||||
}
|
IBinarySerializable newavList = new avatarguideTestList();
|
||||||
```
|
var readOK = FileManager.ReadBinaryDataFromFile(Path.Combine(path, "avatarguideTest.dat"), ref newavList);
|
||||||

|
if (readOK)
|
||||||
|
{
|
||||||
##### Unity解析二进制
|
ConsoleHelper.WriteInfoLine(newavList.ToString());
|
||||||
将二进制文件(后缀必须是.bytes)放在Resources目录,然后通过Resources.Load接口加载
|
}
|
||||||
```
|
else
|
||||||
var bytes = Resources.Load<TextAsset>("avatarguideTest");
|
{
|
||||||
if (bytes == null)
|
ConsoleHelper.WriteErrorLine("读取失败");
|
||||||
{
|
}
|
||||||
return;
|
```
|
||||||
}
|
|
||||||
IBinarySerializable newavList = new avatarguideTestConfig();
|

|
||||||
var readOK = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref newavList);
|
|
||||||
if (readOK)
|
##### Unity解析二进制
|
||||||
{
|
|
||||||
Debug.Log(newavList.ToString());
|
将二进制文件(后缀必须是.bytes)放在Resources目录,然后通过Resources.Load接口加载
|
||||||
|
|
||||||
//根据Id查询数据
|
```
|
||||||
//var avatarguideTest = (avatarguideTestConfig)newavList;
|
var bytes = Resources.Load<TextAsset>("avatarguideTest");
|
||||||
//var obj = avatarguideTest.QueryById(2);
|
if (bytes == null)
|
||||||
//if (obj != null && obj.Count() > 0)
|
{
|
||||||
// Debug.Log(obj.FirstOrDefault().ToString());
|
return;
|
||||||
}
|
}
|
||||||
else
|
IBinarySerializable newavList = new avatarguideTestConfig();
|
||||||
{
|
var readOK = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref newavList);
|
||||||
Debug.LogError("数据读取错误");
|
if (readOK)
|
||||||
}
|
{
|
||||||
```
|
Debug.Log(newavList.ToString());
|
||||||
|
|
||||||
#### 泛型读表
|
//根据Id查询数据
|
||||||
```
|
//var avatarguideTest = (avatarguideTestConfig)newavList;
|
||||||
T ReadTable<T>(string tableName) where T : IBinarySerializable, new()
|
//var obj = avatarguideTest.QueryById(2);
|
||||||
{
|
//if (obj != null && obj.Count() > 0)
|
||||||
var bytes = LoadTextAsset(tableName);
|
// Debug.Log(obj.FirstOrDefault().ToString());
|
||||||
if (bytes != null)
|
}
|
||||||
{
|
else
|
||||||
IBinarySerializable data = new T();
|
{
|
||||||
var readOK = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data);
|
Debug.LogError("数据读取错误");
|
||||||
if (readOK)
|
}
|
||||||
{
|
```
|
||||||
return (T)data;
|
|
||||||
}
|
#### 泛型读表
|
||||||
else
|
|
||||||
{
|
```
|
||||||
Debug.LogError($"{tableName}解析出错 类型{typeof(T)}");
|
T ReadTable<T>(string tableName) where T : IBinarySerializable, new()
|
||||||
}
|
{
|
||||||
}
|
var bytes = LoadTextAsset(tableName);
|
||||||
return default(T);
|
if (bytes != null)
|
||||||
}
|
{
|
||||||
```
|
IBinarySerializable data = new T();
|
||||||
##### 查询数据
|
var readOK = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data);
|
||||||
```
|
if (readOK)
|
||||||
var avatarguideTest = (avatarguideTestConfig)newavList;
|
{
|
||||||
var obj = avatarguideTest.QueryById(2);
|
return (T)data;
|
||||||
if (obj != null && obj.Count() > 0)
|
}
|
||||||
ConsoleHelper.WriteInfoLine(obj.FirstOrDefault().ToString());
|
else
|
||||||
```
|
{
|
||||||
|
Debug.LogError($"{tableName}解析出错 类型{typeof(T)}");
|
||||||
#### 自动化拷贝批处理
|
}
|
||||||
```
|
}
|
||||||
@echo off
|
return default(T);
|
||||||
|
}
|
||||||
echo "开始拷贝jsons"
|
```
|
||||||
for %%i in (*.dat) do (
|
|
||||||
echo begin copy... %%i
|
##### 查询数据
|
||||||
copy /y %%~nxi ..\..\hola_unity\Assets\Resources\Config\%%~nxi
|
|
||||||
echo copy complate ... %%i
|
```
|
||||||
)
|
var avatarguideTest = (avatarguideTestConfig)newavList;
|
||||||
echo "拷贝完成"
|
var obj = avatarguideTest.QueryById(2);
|
||||||
|
if (obj != null && obj.Count() > 0)
|
||||||
pause
|
ConsoleHelper.WriteInfoLine(obj.FirstOrDefault().ToString());
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 扩展类方法
|
#### 自动化拷贝批处理
|
||||||
上面的config类采用的是partical class 就是为了方便扩展自定义的方法,如果想要添加自定义方法也定义一个partical class文件作为扩展即可
|
|
||||||
|
```
|
||||||
#### 待扩展的功能
|
@echo off
|
||||||
目前还不是最理想的状态,还有很多可以扩展完善的功能,如下:
|
|
||||||
|
echo "开始拷贝jsons"
|
||||||
* 支持生成各种类型的文件,例如json、xml、proto、lua等
|
for %%i in (*.dat) do (
|
||||||
* 支持生成各种语法的模板代码
|
echo begin copy... %%i
|
||||||
* 支持Excel数据配置规范性检测,例如手误配置不符合规范导致加载异常,例如大小写逗号(肉眼容易忽略),或者空格等等
|
copy /y %%~nxi ..\..\hola_unity\Assets\Resources\Config\%%~nxi
|
||||||
* 支持Excel字段客户端服务器可选项
|
echo copy complate ... %%i
|
||||||
* 支持更多自定义数据类型扩展
|
)
|
||||||
* 支持枚举类型
|
echo "拷贝完成"
|
||||||
|
|
||||||
#### 代码
|
pause
|
||||||
https://github.com/dingxiaowei/ExcelTool 喜欢麻烦点个star吧
|
```
|
||||||
|
|
||||||
#### Unity客户端使用范例
|
#### 扩展类方法
|
||||||
采用的美术效果机型适配商业化解决方案Demo
|
|
||||||
https://github.com/dingxiaowei/DeviceGrading
|
上面的config类采用的是partical class 就是为了方便扩展自定义的方法,如果想要添加自定义方法也定义一个partical class文件作为扩展即可
|
||||||
优雅的表格使用范本
|
|
||||||
|
#### 待扩展的功能
|
||||||
|
|
||||||
|
目前还不是最理想的状态,还有很多可以扩展完善的功能,如下:
|
||||||
|
|
||||||
|
* 支持生成各种类型的文件,例如json、xml、proto、lua等
|
||||||
|
* 支持生成各种语法的模板代码
|
||||||
|
* 支持Excel数据配置规范性检测,例如手误配置不符合规范导致加载异常,例如大小写逗号(肉眼容易忽略),或者空格等等
|
||||||
|
* 支持Excel字段客户端服务器可选项
|
||||||
|
* 支持更多自定义数据类型扩展
|
||||||
|
* 支持枚举类型
|
||||||
|
|
||||||
|
#### 代码
|
||||||
|
|
||||||
|
https://github.com/dingxiaowei/ExcelTool 喜欢麻烦点个star吧
|
||||||
|
|
||||||
|
#### Unity客户端使用范例
|
||||||
|
|
||||||
|
采用的美术效果机型适配商业化解决方案Demo
|
||||||
|
https://github.com/dingxiaowei/DeviceGrading
|
||||||
|
优雅的表格使用范本
|
||||||
|
todo:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user