根据Excel 自动生成对应类,以及将Excel中的数据以二进制的方式持久化的思路 java代码讲解

在游戏开发中,通常都有大量的配置数据;这些数据通常都是 策划和程序协商之后,由策划填入,程序根据 约定,将数据 解析,在程序中使用;

以下面的的配置为例:

在这里插入图片描述

根据约定,第一行为 字段名,第二行为字段类型,3-5行随便策划写什么;但是id不能为空,第六行之后为 正式数据;

excel 的读取 网上搜一下就一大堆,这里不过多说;

下面是我的初步思路:

在这里插入图片描述

我先手动用 字符串 拼接了一个 类;只包含了 类名,字段类型,字段名;

我枚举了 配置中 常用的4种类型:

在这里插入图片描述

下面就是我的具体实现思路:

1: 先用工具读取 excel中的数据

2: 读取配置表的第一行,将所有的字段 记录到 fieldList 中

3: 读取配置表的第二行,将对应的类型 记录到 typeList 中

在这里插入图片描述

read里有当前excel的所有数据,使用hutool工具 读取的;

然后就是循环,

在这里插入图片描述

到了这里,我们就知道了 这个配置表有多少个字段,以及对应的类型了;

然后我根据这两个List,生成类

    /**
     * 生成类
     *
     * @param desc    注释,在类名 上面,标注 当前的类 是根据 哪个 excel生成的
     * @param clsName 类名 JavaClassName  不要带后缀
     * @param types   List<EClaseType> types
     * @param fields  List<String> fields
     * @throws IOException
     */
    public static void generateClass
    (String desc, String clsName, List<EClaseType> types, List<String> fields) throws IOException {

        // 保存要创建的类中的所有字符串 文本
        StringBuilder str = new StringBuilder();

        // 换行符
        String property = System.getProperty("line.separator");
        // 创建java文件,suffix的 值是.java ,如果以后要为其他语言提供支持,可以修改配置,比如改为 .cs
        File txtFile = TxtExport.createTxtFile(classTargetPath, clsName + suffix);

        // 写入包头
        str.append(pack).append(property).append(property);
        // 写入该类是根据哪个 excle生成的
        str.append("// ").append(desc).append(property);
        // 写入public class ClassName {
        str.append("public class ").append(clsName).append(" {").append(property).append('\t');

        for (int i = 0; i < types.size(); i++) {
            str.append("private ");
            switch (types.get(i)) {
                case INT:
                    str.append("int ").append(fields.get(i)).append(";").append(property);
                    break;
                case INT1:
                    str.append("int[] ").append(fields.get(i)).append(";").append(property);
                    break;
                case INT2:
                    str.append("int[][] ").append(fields.get(i)).append(";").append(property);
                    break;
                case STRING:
                    str.append("String ").append(fields.get(i)).append(";").append(property);
                    break;
            }

            if (i != types.size() - 1) {
                str.append('\t');
            }
        }

        str.append(property);

        for (int i = 0; i < types.size(); i++) {
            str.append('\t').append("public ");
            switch (types.get(i)) {
                case INT:
                    str.append("int ").append("get_").append(fields.get(i)).append("() {").append(property);
                    str.append("\t\t");
                    str.append("return ").append(fields.get(i)).append(";");
                    str.append(property).append('\t');
                    str.append('}').append(property);
                    break;
                case INT1:
                    str.append("int[] ").append("get_").append(fields.get(i)).append("() {").append(property);
                    str.append("\t\t");
                    str.append("return ").append(fields.get(i)).append(";");
                    str.append(property).append('\t');
                    str.append('}').append(property);
                    break;
                case INT2:
                    str.append("int[][] ").append("get_").append(fields.get(i)).append("() {").append(property);
                    str.append("\t\t");
                    str.append("return ").append(fields.get(i)).append(";");
                    str.append(property).append('\t');
                    str.append('}').append(property);
                    break;
                case STRING:
                    str.append("String ").append("get_").append(fields.get(i)).append("() {").append(property);
                    str.append("\t\t");
                    str.append("return ").append(fields.get(i)).append(";");
                    str.append(property).append('\t');
                    str.append('}').append(property);
                    break;
            }

            str.append(property);
        }
        // 补上右 花括号
        str.append("}");

		// 将组装的 字符串 写入到文件中
        TxtExport.writeTxtFile(txtFile, str);
    }
   

运行后,生成了下面的代码

在这里插入图片描述

对于类的生成,这里就完成了.

下面应该是将excel的数据 转为二进制 持久化到文件中;

这里先说一下我将数据转二进制的思路:
我根据 类中的字段顺序,比如第一个是int,则直接将 excel中的这个int 值 转为byte,写入到文件;
如果是String,则先将excel中的文字转为utf8的byte数据,记录长度,(长度一般不会超过short吧,所以用short类型记录)
比如 "洛天依" 三个汉字,如果取长度是3,但是取UTF8的bytes 长度,就是9了(一个汉字占3byte);
我会先写入short类型的9,然后将 "洛天依" 三个汉字转为 byte[] 是:
[-26, -76, -101, -27, -92, -87, -28, -66, -99]
java系的同学可以把 这个数组 new为String 看看对不对..
当这个类 加载 我们生成的bytes文件时,
第一个字段是int,直接redisInt(); 写入到id;
第二个字段是String,需要先readShort,获取到值为9的short,然后从后面读9个byte到数组,最后转为对象
代码如下:
            int name1 = dis.readShort();
            byte[] str = new byte[name1];
            for (int i = 0; i < name1; i++) {
                str[i] = dis.readByte();
            }
            name = new String(str);
数组和字符串一样,先取长度;
二维数组稍微复杂点,需要先写入外围数组的长度,然后再写入内围数组的长度,然后再写内围0下标的值
			int reward1 = dis.readShort();
            reward = new int[reward1][];
            for (int i = 0; i < reward1; i++) {
                int reward2 = dis.readShort();
                reward[i] = new int[reward2];
                for (int j = 0; j < reward2; j++) {
                    reward[i][j] = dis.readInt();
                }
            }

思路到这里就完了,下面说实现

根据 上面的 typeList ,我们可以写一个 switch,判断是要写入到bytes的字段的类型;
如果是int,直接将 数值写入 bytes文件即可
如果是String,需要先知道 这个字符串的 byte长度,
数组也一样,代码如下:

在这里插入图片描述

-----------------------------暂时先写到这里,后续再补-----------------------------

我们可以使用字符串 来组装一个类了,自然可以将 excel 中,一行的数据,封装为一个对象;这个过程我就不贴了;
对象该如何持久化为 二进制呢?
比如我贴的excel图片,第六行,也就是id为1的那一行.
id 为1,name为nnn,age为22,grade为1+2+3,reward为1+1;2+2
我们前面已经记录了这个excel中 所有的字段类型了;就是List那个;
循环这个List
第一个类型是int类型,值为1,那么我们将 1这个值转为byte[],写入文件;
第二个值为字符串,先取整个字符串的长度,记做 short即可(如果你觉得可能会超出这个长度,那记做int也可以,那样的话,后面读取的时候也要是这个长度类型);这个字符串 nnn 的长度为3,写入文件;然后将nnn转为 btye[] ,写入文件;
后面的age,grade 就不再说了,可以参考上面的;直接说reward;
因为reward是二维数组,我们要先取 reward[]的长度,写入文件,再取reward[0]的长度,写入文件,然后再写两个1的值;然后再取reward[1]的长度,再写入;这里面都是int类型,参考上面int即可;

到这里,这个对象就已经被写入到 文件中了,下面说 如何读取;

// 读取一个文件
DataInputStream dis = new DataInputStream(new FileInputStream("C:\\Users\\HASEE\\Desktop\\excel\\test.bytes"));
循环 List ,得知第一个 数据是int,使用dis.readInt(); 读取第一个数字,赋值给id;
第二个是字符串,那我们就先 读取这个字符串的长度 dis.readShort();(注意,如果你前面用的是int,这里也要读int);
        // 读字符串长度
        short i5 = dis.readShort();
        byte[] str = new byte[i5];
        // 根据上面 读取到的长度,循环读取 后续的 byte,最后转为 字符串
        for (int j = 0; j < i5; j++) {
            str[j] = dis.readByte();
        }
        String s = new String(str);
下面是 二维数组;根据我们之前的储存方式: 我们先读取int[] 的长度;(外循环的长度)
        // 二维数组 int[] 的长度 --外循环的长度
        short arrLen = dis.readShort();
        int[][] arrs = new int[arrLen][];

        for (int j = 0; j < arrLen; j++) {
            // arrs[j][k] 的长度 --内循环
            short i2 = dis.readShort();
            arrs[j] = new int[i2];
            for (int k = 0; k < i2; k++) {
                arrs[j][k] = dis.readInt();
            }
        }

至此,就将 一个 对象 存为二进制,以及 再次转为对象的过程 说完了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值