Home

Awesome

tabtoy v3

高性能表格数据导出工具

tabtoylogo

特性

迭代历程

导出第一个表

类型表

准备一个电子表格命名为: Type.xlsx

类型表用于定义表格中表头以及用到的类型

表格内容如下:

种类对象类型标识名字段名字段类型数组切割索引标记
表头MyDataIDIDint32
表头MyData名称Namestring

数据表

准备一个电子表格命名为: MyData.xlsx

表格内容如下:

ID名称
1坦克
2法师

索引表

模式表类型表文件名
类型表Type.xlsx
数据表MyDataMyData.xlsx

注意 数据表的表类型需要与类型表里的对象类型对应

编写导出shell

下载tabtoy

tabtoy.exe -mode=v3 -index=Index.xlsx -json_out=table_gen.json

完整例子文件

导出数据/源码/类型

Golang使用表格导出的JSON数据

导出命令行:

tabtoy.exe -mode=v3 -index=Index.xlsx -package=main -go_out=table_gen.go -json_out=table_gen.json

读取数据源码:

	var Tab = NewTable()

	// 表加载前清除之前的手动索引和表关联数据
	Tab.RegisterPreEntry(func(tab *Table) error {
		fmt.Println("tab pre load clear")
		return nil
	})

	// 表加载和构建索引后,需要手动处理数据的回调
	Tab.RegisterPostEntry(func(tab *Table) error {
		fmt.Println("tab post load done")
		fmt.Printf("%+v\n", tab.ExampleDataByID[200])

		fmt.Println("KV: ", tab.GetKeyValue_ExampleKV().ServerIP)
		return nil
	})

	err := tabtoy.LoadFromFile(Tab, "../json/table_gen.json")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

完整Golang例子

C#使用表格导出二进制数据

导出命令行:

tabtoy.exe -mode=v3 -index=Index.xlsx -package=main -csharp_out=table_gen.cs -binary_out=table_gen.bin

读取数据源码:

using (var stream = new FileStream("../../../../binary/table_gen.bin", FileMode.Open))
{
    stream.Position = 0;

    var reader = new tabtoy.TableReader(stream);


    var tab = new main.Table();

    try
    {
        tab.Deserialize(reader);
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
    
    // 建立所有数据的索引
    tab.IndexData();

    // 表遍历
    foreach (var kv in tab.ExampleData) 
    {
        Console.Write("{0} {1}\n",kv.ID, kv.Name);
    }

    // 直接取值
    Console.WriteLine(tab.ExtendData[1].Additive);

    // KV配置
    Console.WriteLine(tab.GetKeyValue_ExampleKV().ServerIP);
}

完整C#例子

Java使用表格导出的JSON数据

导出命令行:

tabtoy.exe -mode=v3 -index=Index.xlsx -package=main -java_out=Table.java -json_out=table_gen.json

读取数据源码:

import main.Table;
import com.alibaba.fastjson.JSON;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

public class Main {

    // 从文件读取数据
    private static String readFileAsString(String fileName)throws Exception
    {
        return new String(Files.readAllBytes(Paths.get(fileName)));
    }
    public static void main(String[] args) throws Exception {

        // 从文件读取配置表
        String data = null;
        try {
            data = readFileAsString("table_gen.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 表格数据
        Table tab;

        // 从json序列化出对象
        tab = JSON.parseObject(data, Table.class);

        if(tab == null){
            throw new Exception("parse table failed");
        }

        // 构建索引
        tab.BuildData();

        // 测试输出
        for(Map.Entry<Integer, Table.ExampleData> def : tab.ExampleDataByID.entrySet()){
            System.out.println(def.getValue().Name);
        }
    }
}

完整Java例子

Lua使用表格导出的Lua数据(测试中)

导出命令行:

tabtoy.exe -mode=v3 -index=Index.xlsx -lua_out=table_gen.lua

读取数据源码:

    -- 加载
    local tab = {}
    require("table_gen").init(tab)
    
    -- 遍历表
    print("Iterate lua table by order:")
    for _, v in ipairs(tab.ExampleData) do
        print(v.ID, v.Name)
    end

    -- 通过索引访问
    print("Access index table data:")
    print(tab.ExampleDataByID[300].ID)

    -- 枚举类型访问
    print("Use generated enum:")
    print(tab.ActorType.Pharah,  tab.ActorType[3])

完整Lua例子

将表格类型信息导出为JSON格式

导出命令行:

tabtoy -mode=v3 -index=Index.xlsx -jsontype_out=type_gen.json 

导出为Protobuf格式

tabtoy可以将表类型及结构输出为Google Protobuf的proto格式, 同时输出与之对应的二进制格式(*.pbb)

使用Protobuf的SDK即可方便的将表数据提供给所有Protobuf支持的语言

以下例子展示Golang使用Protobuf读取表格输出文件

tabtoy -mode=v3 -index=Index.xlsx -proto_out=table.proto 
tabtoy -mode=v3 -index=Index.xlsx -pbbin_out=all.pbb

下载地址: https://github.com/protocolbuffers/protobuf/releases

go install google.golang.org/protobuf/cmd/protoc-gen-go
protoc --go_out=. ./table.proto -I .

完整Golang使用Protobuf例子

按表导出

tabtoy默认情况下, 均是将数据, 源码一次性导出.出于以下原因,tabtoy支持按表导出数据

Golang按需读取JSON数据

导出命令行:

tabtoy -mode=v3 -index=Index.xlsx -package=main -go_out=table_gen.json -json_dir=.

读取数据源码:

	var TabData = NewTable()
	err := tabtoy.LoadTableFromFile(TabData, "../jsondir/ExampleData.json")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println("load specified table: ExampleData")
	for k, v := range TabData.ExampleDataByID {
		fmt.Println(k, v)
	}

	// 分表加载时, 不会触发pre/post Handler
	var TabKV = NewTable()
	err = tabtoy.LoadTableFromFile(TabKV, "../jsondir/ExampleKV.json")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println("load specified table: ExampleKV")
	for k, v := range TabKV.ExampleKV {
		fmt.Println(k, v)
	}

完整Golang例子

Lua按需读取Lua数据

导出命令行:

tabtoy -mode=v3 -index=Index.xlsx -lua_dir=.

读取数据源码:

    local tabData = {}
    require("ExampleData").init(tabData)
    require("ExtendData").init(tabData)

    print("Load 2 tables into one lua table:")
    for _, v in ipairs(tabData.ExampleData) do
        print(v.ID, v.Name)
    end
    for _, v in ipairs(tabData.ExtendData) do
        print(v.Additive)
    end

    print("Load kv table into single lua table:")
    local kvData = {}
    require("ExampleKV").init(kvData)
    for _, v in ipairs(kvData.ExampleKV) do
        print(v.ServerIP, v.ServerPort)
    end

    -- lua枚举是可选功能, 根据需要加载
    local tabType = {}
    require("_TableType").init(tabType)
    print("Use generated enum:")
    print(tabType.ActorType.Pharah,  tabType.ActorType[3])

完整Lua例子 导出的Lua表

C#按需读取二进制数据

导出命令行:

tabtoy -mode=v3 -index=Index.xlsx -package=main -csharp_out=table_gen.cs -binary_dir=.

读取数据源码:

 static void LoadTableByName(main.Table tab,  string tableName)
{
    using (var stream = new FileStream(string.Format("../../../../binary/{0}.bin", tableName), FileMode.Open))
    {
        stream.Position = 0;

        var reader = new tabtoy.TableReader(stream);
        try
        {
            tab.Deserialize(reader);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }
    
    tab.IndexData(tableName);
}

static void LoadSpecifiedTable()
{
    var tabData = new main.Table();

    LoadTableByName(tabData, "ExampleData");
    LoadTableByName(tabData, "ExtendData");

    Console.WriteLine("Load table merged into one class");
    // 表遍历
    foreach (var kv in tabData.ExampleData)
    {
        Console.Write("{0} {1}\n", kv.ID, kv.Name);
    }
    // 表遍历
    foreach (var kv in tabData.ExtendData)
    {
        Console.Write("{0}\n", kv.Additive);
    }

    Console.WriteLine("Load KV table into one class");
    var tabKV = new main.Table();
    LoadTableByName(tabKV, "ExampleKV");

    // KV配置
    Console.WriteLine(tabKV.GetKeyValue_ExampleKV().ServerIP);
}

完整C#例子

Golang使用Protobuf按需读取二进制数据

Golang例子

特色功能

定义和使用枚举

种类对象类型标识名字段名字段类型数组切割索引标记
枚举ActorTypeNoneint320
枚举ActorType法鸡Pharahint321
枚举ActorType狂鼠Junkratstring2
枚举ActorType源氏Genjiint323
枚举ActorType天使Mercystring4
表头ExampleData类型TypeActorType
类型
狂鼠
Genji

使用数组

种类对象类型标识名字段名字段类型数组切割索引标记
表头ExampleData技能列表Skillint32<code>|</code>
技能列表
<code>2|3</code>
1

输出:

[2, 3]

[ 1 ]

使用多列数组

种类对象类型标识名字段名字段类型数组切割索引标记
表头ExampleData技能列表Skillint32<code>|</code>
技能列表技能列表
23
1

输出:

[2, 3 ]

[ 1, 0 ]

为字段建立索引

种类对象类型标识名字段名字段类型数组切割索引标记
表头ExampleDataIDIDint32

生成代码中, 会自动对数据创建索引, 例如:

ExampleDataByID map[int32]*ExampleData

表拆分

将ExampleData表, 拆为Data.csv, Data2.csv表

模式表类型表文件名
类型表Type.xlsx
数据表ExampleDataData.csv
数据表ExampleDataData2.csv

每个表中的字段可按需填写

KV表

准备类型表:

模式表类型表文件名
类型表Type.xlsx
数据表ExampleKVKV.csv

准备KV表:

字段名字段类型标识名数组切割标记
ServerIPstring服务器IP8.8.8.8
ServerPortuint16服务器端口1024

空行分割

表格数据如下:

ID名称
1坦克
2法师
(空行)
3治疗

导出数据

导表工具在识别到空行后, 空行后的数据将被忽略

行数据注释

表格数据如下:

ID名称
1坦克
#2法师
3治疗

导出数据

在任意表的首列单元格中首字符为#时,该行所有数据不会被导出

列数据注释

表格数据如下:

ID#名称
1坦克
2法师
3治疗

导出数据

表头中, 列字段首字符为#时,该列所有数据按默认值导出

不导出指定表

实现此功能需要使用到TagAction, 参考下面例子配置:

在Index表中:

模式表类型表文件名标记
数据表EffectEffect.csvclient
数据表PasswordServer.csvserver
--tag_action=nogentab:server

表示, 不导出带有server标记的所有表格

--tag_action=nogentab:client

表示, 不导出带有client标记的所有表格

不输出指定列数据

实现此功能需要使用到TagAction, 参考下面例子配置:

在Type表中:

种类对象类型标识名字段名字段类型数组切割索引标记
表头ExampleData特效IDEffectIDint32client
表头ExampleData概率Ratefloatserver

表中的特效ID, 只希望客户端导出数据中包含EffectID, 同时服务器导出数据中只包含Rate, 不希望将Rate字段导入客户端数据 客户端导出为二进制, 服务器导出为json

此时在相应字段所在的Type表中的"标记" 一列增加如表所示标记(如标记列不存在, 请新建)

将原有导出流程拆分为客户端导出和服务器导出, 分两次分别导出不同需求的数据

--tag_action=nogenfield_binary:server

表示: server标记的字段不导出到二进制

--tag_action=nogenfield_json:client

表示: client标记的字段不导出到json完整文件

TagAction参考说明

格式

--tag_action=action1:tag1+tag2|action2:tag1+tag3

action类型

action适用范围功能
nogenfield_jsonType表被标记的字段不导出到json完整文件中
nogenfield_jsondirType表被标记的字段不导出到每个表文件json
nogenfield_binaryType表被标记的字段不导出到二进制中
nogenfield_pbbinType表被标记的字段不导出到Protobuf二进制中
nogenfield_luaType表被标记的字段不导出到Lua中
nogenfield_csharpType表被标记的字段不导出到C#中
nogentabIndex表被标记的表不会导出到任何输出中

启用缓冲

命令行中加入-usecache=true, 将启用缓存功能, 加速导出速度

-cachedir参数设定缓存目录, 默认换出到tabtoy当前目录下的.tabtoycache目录

FAQ

V2版本说明

备注

感觉不错请star, 谢谢!

知乎: http://www.zhihu.com/people/sunicdavy

提交bug及特性: https://github.com/davyxu/tabtoy/issues