使用树结构的方式对Java的byte数组进行快速解析和构建
Comment相比于ByteArrayList和BytesReader,这种方式可以更直观的体现出这段byte数组是什么样的结构,并高效进行重复解析和构建
对各种数据类型进行定义
- 对于无符号数据类型和有符号数据类型,进行自定义类型,这样更直观
- 对于一段数据表示后续数据长度的可变数据类型进行定义,包括:
- 第一字节为无符号8位 表示后续的内容长度 长度后续紧跟内容
- 前两字节为小端无符号16位 表示后续的内容长度 长度后续紧跟内容
- 前四字节为小端无符号32位 表示后续的内容长度 长度后续紧跟内容
- 前两字节为大端无符号16位 表示后续的内容长度 长度后续紧跟内容
- 前四字节为大端无符号32位 表示后续的内容长度 长度后续紧跟内容
- 有时候末尾的数据不进行上述定义为任意长度,直接表示剩余数据都为某种数据,对这种数据进行定义
- 在某个节点中包含很多子节点,有时候这些子节点是相同的,一般将这些子节点额外定义以便复用
实现
根据以上要点,实现如下定义:
/**
* 数据的类型,表示一段byte数组是什么类型的数据
*/
public interface DataType {
/**
* 无符号8位 java用short接收
*/
int TYPE_U8 = 0;
/**
* 有符号8位 byte
*/
int TYPE_S8 = 1;
/**
* 无符号16位 java用int接收
*/
int TYPE_U16 = 2;
/**
* 有符号16位 short
*/
int TYPE_S16 = 3;
/**
* 无符号32位 java用long接收
*/
int TYPE_U32 = 4;
/**
* 有符号32位 int
*/
int TYPE_S32 = 5;
/**
* 无符号64位 目前不支持
*/
int TYPE_U64 = 6;
/**
* 有符号64位 long
*/
int TYPE_S64 = 7;
/**
* float
*/
int TYPE_FLOAT = 8;
/**
* double
*/
int TYPE_DOUBLE = 9;
/**
* 可变数据类型1 第一字节为无符号8位 表示后续的内容长度 长度后续紧跟内容
*/
int TYPE_MUABLE0 = 10;
/**
* 可变数据类型2 前两字节为小端无符号16位 表示后续的内容长度 长度后续紧跟内容
*/
int TYPE_MUABLE1 = 11;
/**
* 可变数据类型3 前四字节为小端无符号32位 表示后续的内容长度 长度后续紧跟内容
*/
int TYPE_MUABLE2 = 12;
/**
* 可变数据类型4 前两字节为大端无符号16位 表示后续的内容长度 长度后续紧跟内容
*/
int TYPE_MUABLE1_BE = 13;
/**
* 可变数据类型5 前四字节为大端无符号32位 表示后续的内容长度 长度后续紧跟内容
*/
int TYPE_MUABLE2_BE = 14;
/**
* 树结构类型
*/
int TYPE_TREE = 100;
/**
* 原始数据类型 byte[]
* 当初始化时指定了长度时在获取时会获取对应长度的数据,若未指定长度在获取时会获取剩余的所有数据
*/
int TYPE_RAW = 200;
}编写一个描述类进行解析时无需关心数据的具体内容,使用此类进行构建,解析时根据此类根据描述类对其进行解析即可
节点的描述中表示了该节点的数据类型、部分数据类型和大小端/**
* 对于 byte数组 的描述 表示这段byte数组是:什么类型,长度为多少,是大端还是小端
* 构造时如果不传入是否大小端,默认是小端
*/
public class DataDescribe {
/**
* 数据类型 {@link DataType}
*/
public int type;
/**
* 数据长度
*/
public int length;
/**
* 是否为小端
*/
public boolean isLe;
/**
* 大多数数据的长度初始化时其实都是固定的,没必要在构造时手动填入
* 除了 {@link DataType#TYPE_RAW} 可能需要传入长度,其他都不需要
*/
public DataDescribe(int type, boolean isLe) {
this.type = type;
this.isLe = isLe;
switch (type) {
case DataType.TYPE_U8:
case DataType.TYPE_S8:
length = 1;
break;
case DataType.TYPE_U16:
case DataType.TYPE_S16:
length = 2;
break;
case DataType.TYPE_U32:
case DataType.TYPE_S32:
length = 4;
break;
case DataType.TYPE_S64:
length = 8;
break;
case DataType.TYPE_FLOAT:
length = 4;
break;
case DataType.TYPE_DOUBLE:
length = 8;
break;
case DataType.TYPE_MUABLE0:
case DataType.TYPE_MUABLE1:
case DataType.TYPE_MUABLE2:
case DataType.TYPE_MUABLE1_BE:
case DataType.TYPE_MUABLE2_BE:
case DataType.TYPE_TREE:
case DataType.TYPE_RAW:
length = 0;
break;
}
}
/**
* 默认小端
*/
public DataDescribe(int type) {
this(type, true);
}
/**
* @param type 数据类型
* @param len 数据长度 除了 {@link DataType#TYPE_RAW} 可能需要传入长度,其他实际上都不需要
* @param le 是否是小端
*/
public DataDescribe(int type, int len, boolean le) {
this.type = type;
length = len;
isLe = le;
}
/**
* 默认小端
*/
public DataDescribe(int type, int len) {
this(type, len, true);
}
}
进行树的实现
异常处理:
- 设置指定的位置的数据与描述中的位置不匹配时不会进行设置,对应的位置会为null
- 获取指定的位置的数据与描述中的位置不匹配时会默认返回0
public class Tree {
/**
* 节点 根据des中的顺序存储着对应的数据
*/
private SparseArray<Tree> node = new SparseArray<>();
/**
* 节点的描述 表示节点{@link Tree#node}下存储的是哪些些数据
*/
private DataDescribe[] des;
/**
* 代表当前节点下的所有内容的数据
*/
private byte[] data;
/**
* 根据节点的描述初始化本类的描述
*/
public Tree(@NonNull DataDescribe[] des) {
this.des = des;
}
/**
* 会将传入的多个子Tree依次放入 des描述的指定位置
*/
public Tree(@NonNull DataDescribe[] des, Tree... child) {
this.des = des;
int index = -1;
for (Tree tree : child) {
for (int i = index + 1; i < des.length; i++) {
if (des[i].type == DataType.TYPE_TREE) {
index = i;
node.put(index, tree);
break;
}
}
}
}
private Tree(byte b) {
data = new byte[]{b};
}
private Tree(byte[] src) {
data = src;
}
private Tree(short val, boolean isU8, boolean le) {
if (isU8) {
data = new byte[]{(byte) (val & 0xff)};
} else {
data = le ? EndianUtils.toLe(val) : EndianUtils.toBe(val);
}
}
private Tree(int val, boolean isU16, boolean le) {
if (isU16) {
data = le ? EndianUtils.u16ToLe(val) : EndianUtils.u16ToBe(val);
} else {
data = le ? EndianUtils.toLe(val) : EndianUtils.toBe(val);
}
}
private Tree(long val, boolean isU32, boolean le) {
if (isU32) {
data = le ? EndianUtils.u32ToLe(val) : EndianUtils.u32ToBe(val);
} else {
data = le ? EndianUtils.toLe(val) : EndianUtils.toBe(val);
}
}
private Tree(float val, boolean le) {
data = le ? EndianUtils.toLe(val) : EndianUtils.toBe(val);
}
private Tree(double val, boolean le) {
data = le ? EndianUtils.toLe(val) : EndianUtils.toBe(val);
}
private Tree(int type, String val) {
try {
byte[] src = val.getBytes("GBK");
ByteArrayList list = new ByteArrayList();
switch (type) {
case DataType.TYPE_MUABLE0:
if (src.length <= 255) {
list.add((byte) src.length);
list.add(src);
}
break;
case DataType.TYPE_MUABLE1:
if (src.length <= 65535) {
list.add((short) src.length, true);
list.add(src);
}
break;
case DataType.TYPE_MUABLE2:
list.add(src.length, true);
list.add(src);
break;
case DataType.TYPE_MUABLE1_BE:
if (src.length <= 65535) {
list.add((short) src.length, false);
list.add(src);
}
break;
case DataType.TYPE_MUABLE2_BE:
list.add(src.length, false);
list.add(src);
break;
}
data = list.toArray();
} catch (UnsupportedEncodingException ignored) {
}
}
/**
* 设置有符号8位到本节点的指定位置
*/
public Tree setS8(int index, byte val) {
if (index < des.length && des[index].type == DataType.TYPE_S8) {
node.put(index, new Tree(val));
}
return this;
}
/**
* 设置无符号8位到本节点的指定位置
*/
public Tree setU8(int index, short val) {
if (index < des.length && des[index].type == DataType.TYPE_U8) {
node.put(index, new Tree(val, true, des[index].isLe));
}
return this;
}
/**
* 设置有符号16位到本节点的指定位置
*/
public Tree setS16(int index, short val) {
if (index < des.length && des[index].type == DataType.TYPE_S16) {
node.put(index, new Tree(val, false, des[index].isLe));
}
return this;
}
/**
* 设置无符号16位到本节点的指定位置
*/
public Tree setU16(int index, int val) {
if (index < des.length && des[index].type == DataType.TYPE_U16) {
node.put(index, new Tree(val, true, des[index].isLe));
}
return this;
}
/**
* 设置有符号32位到本节点的指定位置
*/
public Tree setS32(int index, int val) {
if (index < des.length && des[index].type == DataType.TYPE_S32) {
node.put(index, new Tree(val, false, des[index].isLe));
}
return this;
}
/**
* 设置无符号32位到本节点的指定位置
*/
public Tree setU32(int index, long val) {
if (index < des.length && des[index].type == DataType.TYPE_U32) {
node.put(index, new Tree(val, true, des[index].isLe));
}
return this;
}
/**
* 设置有符号64位到本节点的指定位置
*/
public Tree setS64(int index, long val) {
if (index < des.length && des[index].type == DataType.TYPE_S64) {
node.put(index, new Tree(val, false, des[index].isLe));
}
return this;
}
/**
* 设置float类型的数据到本节点的指定位置
*/
public Tree setFloat(int index, float val) {
if (index < des.length && des[index].type == DataType.TYPE_FLOAT) {
node.put(index, new Tree(val, des[index].isLe));
}
return this;
}
/**
* 设置double类型的数据到本节点的指定位置
*/
public Tree setDouble(int index, double val) {
if (index < des.length && des[index].type == DataType.TYPE_DOUBLE) {
node.put(index, new Tree(val, des[index].isLe));
}
return this;
}
/**
* 设置byte数组到本节点的指定位置
*/
public Tree setBytes(int index, byte[] val) {
if (index < des.length && des[index].type == DataType.TYPE_RAW) {
node.put(index, new Tree(val));
}
return this;
}
/**
* 设置字符串数据到本节点的指定位置
*/
public Tree setString(int index, String val) {
if (index < des.length && (des[index].type == DataType.TYPE_MUABLE0 ||
des[index].type == DataType.TYPE_MUABLE1 ||
des[index].type == DataType.TYPE_MUABLE2 ||
des[index].type == DataType.TYPE_MUABLE1_BE ||
des[index].type == DataType.TYPE_MUABLE2_BE)) {
node.put(index, new Tree(des[index].type, val));
}
return this;
}
/**
* 设置子节点到本节点的指定位置
*/
public Tree setChildTree(int index, Tree val) {
if (index < des.length && des[index].type == DataType.TYPE_TREE) {
node.put(index, val);
}
return this;
}
public Tree setChildTree(int index, DataDescribe[] des) {
return setChildTree(index, new Tree(des));
}
/**
* 从本节点中指定位置获取无符号8位
*/
public short getU8(int index) {
if (index < des.length && des[index].type == DataType.TYPE_U8) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return field.data[0] < 0 ? (short) (256 + field.data[0]) : (short) (field.data[0]);
}
}
return 0;
}
/**
* 从本节点中指定位置获取有符号8位
*/
public byte getS8(int index) {
if (index < des.length && des[index].type == DataType.TYPE_S8) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return field.data[0];
}
}
return 0;
}
/**
* 从本节点中指定位置获取无符号16位
*/
public int getU16(int index) {
if (index < des.length && des[index].type == DataType.TYPE_U16) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return des[index].isLe ? EndianUtils.le2U16(field.data) : EndianUtils.be2U16(field.data);
}
}
return 0;
}
/**
* 从本节点中指定位置获取有符号16位
*/
public short getS16(int index) {
if (index < des.length && des[index].type == DataType.TYPE_S16) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return des[index].isLe ? EndianUtils.le2Short(field.data) : EndianUtils.be2Short(field.data);
}
}
return 0;
}
/**
* 从本节点中指定位置获取无符号32位
*/
public long getU32(int index) {
if (index < des.length && des[index].type == DataType.TYPE_U32) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return des[index].isLe ? EndianUtils.le2U32(field.data) : EndianUtils.be2U32(field.data);
}
}
return 0;
}
/**
* 从本节点中指定位置获取有符号32位
*/
public int getS32(int index) {
if (index < des.length && des[index].type == DataType.TYPE_S32) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return des[index].isLe ? EndianUtils.le2Int(field.data) : EndianUtils.be2Int(field.data);
}
}
return 0;
}
/**
* 从本节点中指定位置获取有符号64位
*/
public long getS64(int index) {
if (index < des.length && des[index].type == DataType.TYPE_S64) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return des[index].isLe ? EndianUtils.le2Long(field.data) : EndianUtils.be2Long(field.data);
}
}
return 0;
}
/**
* 从本节点中指定位置获取float类型数据
*/
public float getFloat(int index) {
if (index < des.length && des[index].type == DataType.TYPE_FLOAT) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return des[index].isLe ? EndianUtils.le2Float(field.data) : EndianUtils.be2Float(field.data);
}
}
return 0;
}
/**
* 从本节点中指定位置获取double类型数据
*/
public double getDouble(int index) {
if (index < des.length && des[index].type == DataType.TYPE_DOUBLE) {
Tree field = node.get(index);
if (field != null && field.data != null) {
return des[index].isLe ? EndianUtils.le2Double(field.data) : EndianUtils.be2Double(field.data);
}
}
return 0;
}
/**
* 从本节点中指定位置获取byte数组
*/
public byte[] getBytes(int index) {
if (index < des.length && des[index].type == DataType.TYPE_RAW) {
Tree field = node.get(index);
if (field != null) {
return field.data;
}
}
return null;
}
/**
* 从本节点中指定位置使用指定字符集获取string数据
*/
public String getString(int index, String charSet) {
if (TextUtils.isEmpty(charSet)) return null;
if (index < des.length && (des[index].type == DataType.TYPE_MUABLE0 ||
des[index].type == DataType.TYPE_MUABLE1 ||
des[index].type == DataType.TYPE_MUABLE2 ||
des[index].type == DataType.TYPE_MUABLE1_BE ||
des[index].type == DataType.TYPE_MUABLE2_BE)) {
Tree field = node.get(index);
if (field != null && field.data != null) {
BytesReader reader = new BytesReader(field.data);
switch (des[index].type) {
case DataType.TYPE_MUABLE0:
reader.getU8();
break;
case DataType.TYPE_MUABLE1:
reader.getU16(true);
break;
case DataType.TYPE_MUABLE2:
reader.getU32(true);
break;
case DataType.TYPE_MUABLE1_BE:
reader.getU16(false);
break;
case DataType.TYPE_MUABLE2_BE:
reader.getU32(false);
break;
}
try {
byte[] data = reader.getResidue();
if (data != null) {
return new String(data, charSet);
}
} catch (UnsupportedEncodingException ignored) {
}
}
}
return null;
}
/**
* 从本节点中指定位置使用默认的GBK字符集获取string数据
*/
public String getString(int index) {
return getString(index, "GBK");
}
/**
* 从本节点中指定位置获取子节点
*/
public Tree getChildTree(int index) {
return node.get(index);
}
/**
* 将包含的所有内容转化为byte数组
*/
public byte[] toByteArray() {
ByteArrayList list = new ByteArrayList();
for (int index = 0; index < des.length; index++) {
Tree field = node.get(index);
DataDescribe dataDescribe = des[index];
switch (dataDescribe.type) {
case DataType.TYPE_U8:
case DataType.TYPE_S8:
case DataType.TYPE_U16:
case DataType.TYPE_S16:
case DataType.TYPE_U32:
case DataType.TYPE_S32:
case DataType.TYPE_S64:
case DataType.TYPE_FLOAT:
case DataType.TYPE_DOUBLE:
if (field == null || field.data == null) {
list.addSize(dataDescribe.length);
} else {
list.add(field.data);
}
break;
case DataType.TYPE_MUABLE0:
if (field == null || field.data == null) {
list.add((byte) 0);
} else {
list.add(field.data);
}
break;
case DataType.TYPE_MUABLE1:
if (field == null || field.data == null) {
list.add((short) 0, true);
} else {
list.add(field.data);
}
break;
case DataType.TYPE_MUABLE2:
if (field == null || field.data == null) {
list.add(0, true);
} else {
list.add(field.data);
}
break;
case DataType.TYPE_MUABLE1_BE:
if (field == null || field.data == null) {
list.add((short) 0, false);
} else {
list.add(field.data);
}
break;
case DataType.TYPE_MUABLE2_BE:
if (field == null || field.data == null) {
list.add(0, false);
} else {
list.add(field.data);
}
break;
case DataType.TYPE_TREE:
if (field != null) {
list.add(field.toByteArray());
}
break;
case DataType.TYPE_RAW:
if (field == null || field.data == null) {
list.addSize(dataDescribe.length);
} else {
if (dataDescribe.length != 0 && field.data.length != dataDescribe.length) {
list.add(Arrays.copyOf(field.data, dataDescribe.length));
} else {
list.add(field.data);
}
}
break;
default:
throw new IllegalMonitorStateException("don't have the type " + dataDescribe.type);
}
}
return list.toArray();
}
/**
* 将byte数组 解析为 根据结构描述{@link Tree#des}的 树
*/
public Tree parserByteArray(@NonNull byte[] src) {
if (src != null) {
return parserByteArray(new BytesReader(src));
}
return this;
}
/**
* 将BytesReader对象 解析为 根据结构描述{@link Tree#des}的 树
* <p>
*/
public Tree parserByteArray(@NonNull BytesReader reader) {
if (reader != null) {
for (int index = 0; index < des.length; index++) {
DataDescribe dataDescribe = des[index];
switch (dataDescribe.type) {
case DataType.TYPE_U8:
case DataType.TYPE_S8:
case DataType.TYPE_U16:
case DataType.TYPE_S16:
case DataType.TYPE_U32:
case DataType.TYPE_S32:
case DataType.TYPE_S64:
case DataType.TYPE_FLOAT:
case DataType.TYPE_DOUBLE:
node.put(index, new Tree(reader.getBytes(dataDescribe.length)));
break;
case DataType.TYPE_MUABLE0:
node.put(index, new Tree(reader.getBytes(1 + reader.spyU8())));
break;
case DataType.TYPE_MUABLE1:
node.put(index, new Tree(reader.getBytes(2 + reader.spyU16(true))));
break;
case DataType.TYPE_MUABLE2:
node.put(index, new Tree(reader.getBytes(4 + (int) reader.spyU32(true))));
break;
case DataType.TYPE_MUABLE1_BE:
node.put(index, new Tree(reader.getBytes(2 + reader.spyU16(false))));
break;
case DataType.TYPE_MUABLE2_BE:
node.put(index, new Tree(reader.getBytes(4 + (int) reader.spyU32(false))));
break;
case DataType.TYPE_TREE:
Tree field = node.get(index);
if (field != null) field.parserByteArray(reader);
break;
case DataType.TYPE_RAW:
node.put(index, new Tree(dataDescribe.length > 0 ?
reader.getBytes(dataDescribe.length) : reader.getResidue()));
break;
default:
throw new IllegalMonitorStateException("don't have the type " + dataDescribe.type);
}
}
}
return this;
}
}
使用
定义公共部分
val publicTreeDescribes = arrayOf(DataDescribe(DataType.TYPE_U8), DataDescribe(DataType.TYPE_U8))
对总结构进行定义
val describes = arrayOf(DataDescribe(DataType.TYPE_TREE),
DataDescribe(DataType.TYPE_U8), DataDescribe(DataType.TYPE_S32),
DataDescribe(DataType.TYPE_FLOAT), DataDescribe(DataType.TYPE_U32),
DataDescribe(DataType.TYPE_MUABLE0, stringLength))将描述传入树结构,并将公共部分设置入总结构
因为代码进行了链式实现,可以进行链式调用val paresTree = Tree(describes)
.setChildTree(0, publicTreeDescribes)根据索引进行数据设置或传入数据进行解析根据索引进行获取
数据设置
实际上链式调用即可val buildTree = Tree(describes)
.setChildTree(0, publicTree)
.setU8(1, 3)
.setS32(2, 1)
.setFloat(3, 3.0f)
.setU32(4, 32L)
.setString(5, "123", "UTF-8")设置完毕后直接使用内部方法转化为byte数组,后续进行传输或传输方有直接提供传入方法
val buildTreeResult = buildTree.toByteArray()
数据解析
paresTree.parserByteArray(array)
val childTree = paresTree.getChildTree(0)
val childTreeIndex0 = childTree.getU8(0)
val childTreeIndex1 = childTree.getU8(1)
val index0 = paresTree.getU8(1)
val index1 = paresTree.getS32(2)
val index2 = paresTree.getFloat(3)
val index3 = paresTree.getU32(4)
val index4 = paresTree.getString(5, "UTF-8")