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

根据约定,第一行为 字段名,第二行为字段类型,3-5行随便策划写什么;但是id不能为空,第六行之后为 正式数据;
excel 的读取 网上搜一下就一大堆,这里不过多说;
下面是我的初步思路:

我先手动用 字符串 拼接了一个 类;只包含了 类名,字段类型,字段名;
我枚举了 配置中 常用的4种类型:

下面就是我的具体实现思路:
1: 先用工具读取 excel中的数据
2: 读取配置表的第一行,将所有的字段 记录到 fieldList 中
3: 读取配置表的第二行,将对应的类型 记录到 typeList 中

read里有当前excel的所有数据,使用hutool工具 读取的;
然后就是循环,

到了这里,我们就知道了 这个配置表有多少个字段,以及对应的类型了;
然后我根据这两个List,生成类
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");
File txtFile = TxtExport.createTxtFile(classTargetPath, clsName + suffix);
str.append(pack).append(property).append(property);
str.append("// ").append(desc).append(property);
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];
for (int j = 0; j < i5; j++) {
str[j] = dis.readByte();
}
String s = new String(str);
下面是 二维数组;根据我们之前的储存方式: 我们先读取int[] 的长度;(外循环的长度)
short arrLen = dis.readShort();
int[][] arrs = new int[arrLen][];
for (int j = 0; j < arrLen; j++) {
short i2 = dis.readShort();
arrs[j] = new int[i2];
for (int k = 0; k < i2; k++) {
arrs[j][k] = dis.readInt();
}
}
至此,就将 一个 对象 存为二进制,以及 再次转为对象的过程 说完了