相比于ByteArrayList和BytesReader,这种方式可以更直观的体现出这段byte数组是什么样的结构,并高效进行重复解析和构建

对各种数据类型进行定义

  • 对于无符号数据类型和有符号数据类型,进行自定义类型,这样更直观
  • 对于一段数据表示后续数据长度的可变数据类型进行定义,包括:
    • 第一字节为无符号8位 表示后续的内容长度 长度后续紧跟内容
    • 前两字节为小端无符号16位 表示后续的内容长度 长度后续紧跟内容
    • 前四字节为小端无符号32位 表示后续的内容长度 长度后续紧跟内容
    • 前两字节为大端无符号16位 表示后续的内容长度 长度后续紧跟内容
    • 前四字节为大端无符号32位 表示后续的内容长度 长度后续紧跟内容
  • 有时候末尾的数据不进行上述定义为任意长度,直接表示剩余数据都为某种数据,对这种数据进行定义
  • 在某个节点中包含很多子节点,有时候这些子节点是相同的,一般将这些子节点额外定义以便复用

实现

  1. 根据以上要点,实现如下定义:

    /**
    * 数据的类型,表示一段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;
    }
  2. 编写一个描述类进行解析时无需关心数据的具体内容,使用此类进行构建,解析时根据此类根据描述类对其进行解析即可
    节点的描述中表示了该节点的数据类型、部分数据类型和大小端

    /**
    * 对于 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;
    }
    }

使用

  1. 定义公共部分

    val publicTreeDescribes = arrayOf(DataDescribe(DataType.TYPE_U8), DataDescribe(DataType.TYPE_U8))
  2. 对总结构进行定义

    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))
  3. 将描述传入树结构,并将公共部分设置入总结构
    因为代码进行了链式实现,可以进行链式调用

    val paresTree = Tree(describes)
    .setChildTree(0, publicTreeDescribes)
  4. 根据索引进行数据设置或传入数据进行解析根据索引进行获取

  • 数据设置
    实际上链式调用即可

    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")