ByteBuf 一个用于在通信中的数据解析传输组装的自定义容器类

在做和硬件通信的项目的时候,通信的内容一般都是最基本的byte数组,比如BLE,UART等等方式,传递的都是byte数组。

移动端在接收的时候,就需要去解析byte数组,然后从中通过拼接和或(|)以及位移等运算来得到想要的数据类型,比如说,unsignedByte,short,int,float,double,long,char,string等数据类型。我们当然可以通过java提供的一些IO类来得到想要的数据,可对于一个简单的byte[]的解析就要使用IO这样耗费CPU资源的类来进行,况且这还不涉及到线程之间的同步问题,如果这些问题都要解决,那单单是数据解析这一块儿就够费资源的了。以下给出通过IO来做的方式

        //创建一个源数据,在实际中就是一个byte数组
        byte[] source = new byte[]{0x55, (byte) 0xaa,0x55, (byte) 0xaa,0x03,0x02,0x01};
        //创建IO流
        DataInputStream in = new DataInputStream(new ByteArrayInputStream(source));
        //1.读取Int类型以及其他类型
        in.readShort();
        in.readUnsignedByte();
        in.readUnsignedShort();
        in.readLong();
        //有很多方法。最后要记得调用close方法,同时要考虑到线程同步的问题,最好在外面加上锁

以上是通过IO流来进行数据的解析,易懂,但比较耗费CPU资源。

如果想要通过IO流向外界,比如移动端向嵌入式发送数据,一般都是通过byte[]数据类型来发送的。

 //创建IO输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        DataOutputStream out = new DataOutputStream(byteArrayOutputStream);
        //通过DataOutputStream来输入数据
        out.writeByte(0x55);
        out.writeDouble(2.2);
        out.writeInt(3);
        byte[] bytes = byteArrayOutputStream.toByteArray();
        //通过具体的通信方式把bytes发送给嵌入式设备。要记得close

以上是一种选择,但真的比较耗费资源,同时要创建很多的IO对象来进行持续的数据通信,基于这种情况,自己参考ArrayList,以及DataOutputStream写出了一个ByteBuf (和NIO种的不一样),主要是为了解决以下问题:

1.接收到数据后对容积的扩充,这个采用了ArrayList的原理,具体原理可以自行查看。不过数据结构采用的是byte数组,因为极大的增强了查询效率。

2.方便从容器中按照高-低 位的顺序从中获取支持的数据类型,比如有无符号的byte,有无符号的short,int,float,string,等数据类型。

3.可以通过创建一个ByteBuf实例然后通过append***来填充具体的数据类型,然后通过getByteArray来获取byte数组,然后就可以直接传送到外部设备中。

4.支持直接通过16进制的字符串来填充一个ByteBuf实例,这样增强了协议的可读性。

5.此类是线程安全的类,目前使用的锁都是比较重的synchronized,敏感的数据都使用了volatile保证了多线程下的可见性,byte[]数组通过transient修饰为不可被序列化

以下为具体的代码,因时间节点关系,该类尚未在具体的实际项目中进行使用,纯粹想给以后铺铺路,好在这种事情上省点力气。也希望大家多多指教。

public final class ByteBuf implements java.io.Serializable {
    /**
     * 数组中的byte数组,不支持被序列化
     */
    private transient byte[] buf = null;

    /**
     * 数组中的有效元素个数
     */
    private volatile int size = 0;

    /**
     * 数组的容量
     */
    private volatile int capacity = 100;

    /**
     * 数组的容量因子:当有效元素个数超过 容量*容量因子 就进行扩充 扩充的方式是增加一倍
     */
    private volatile float capacityFactor = 0.75F;

    /**
     * 获取该数组,为防止原数组被修改,copy一份
     * 可以进行通信或者其他用途
     *
     * @return 返回该集合内的有效元素的byte数组
     */
    public final synchronized byte[] getByteArray() {
        return Arrays.copyOfRange(buf, 0, size);
    }


    /**
     * 获取有效元素的个数
     *
     * @return 有效元素的个数
     */
    public synchronized int size() {
        return size;
    }

    /**
     * 按照指定的容量 初始化一个byte数组
     *
     * @param capacity 指定容量
     */
    public ByteBuf(int capacity) {
        this.capacity = capacity;
        buf = new byte[this.capacity];
        size = 0;
    }

    @Override
    public String toString() {
        return hex();
    }

    /**
     * 对当前的ByteBuf进行复制操作
     *
     * @param start
     * @param len
     * @return
     */
    public synchronized ByteBuf copy(int start, int len) {
        if (size() < start + len) {
            throw new ArrayIndexOutOfBoundsException();
        }
        byte[] array = getByteArray();
        byte[] val = Arrays.copyOfRange(array, start, len);
        ByteBuf newByteBuf = new ByteBuf();
        newByteBuf.appendByteArray(val);
        return newByteBuf;
    }


    /**
     * 按照默认的容量 初始化一个byte数组
     */
    public ByteBuf() {
        buf = new byte[this.capacity];
        size = 0;
    }


    /**
     * 向buf中添加data数组
     * 1.先判断要不要扩充
     * 2.copy到buf中
     * 3.更新size
     */
    public synchronized void appendByteArray(byte[] data) {
        int wantSize = size + data.length;
        //如果总共的元素个数超过了总容量*容量因数 就进行拓展
        if (wantSize > capacity * capacityFactor) {
            grow(wantSize);
        }
        System.arraycopy(data, 0, buf, size, data.length);
        size += data.length;
    }

    /**
     * 扩充容量
     */
    private synchronized void grow(int wantSize) {
        byte[] oldBuf = buf;
        capacity = Math.max(wantSize * 2, capacity << 1);
        buf = new byte[capacity];
        System.arraycopy(oldBuf, 0, buf, 0, oldBuf.length);
    }

    /**
     * 清空有效元素,实际上元素数组本身没动,只是告诉外面自己没有有效元素了
     */
    public final synchronized void clear() {
        size = 0;
    }


    /**
     * 删除从start开始的len个字节
     * [start,start+len)
     *
     * @param start 要开始删除的下标
     * @param len   要删除的元素个数
     * @throws ByteBufException
     */
    public synchronized void remove(int start, int len) throws ArrayIndexOutOfBoundsException {
        if (len + start > size) {
            throw new ArrayIndexOutOfBoundsException();
        }
        System.arraycopy(buf, start + len, buf, start, buf.length - len);
        size -= len;
    }

    public synchronized ByteBuf removeWithData(int start, int len) throws ArrayIndexOutOfBoundsException {
        if (start + len > size) {
            throw new ArrayIndexOutOfBoundsException();
        }
        byte[] val = new byte[len];
//        L.e("removeWithData before buf hex = " + hex());

        System.arraycopy(buf, start, val, 0, len);
        System.arraycopy(buf, start + len, buf, start, buf.length - len);
//        L.e("removeWithData after buf hex = " + hex());
//        L.e("removeWithData after val hex = " + Hex.encodeHexStr(val));
        size -= len;
        ByteBuf byteBuf = new ByteBuf();
        byteBuf.appendByteArray(val);
        return byteBuf;
    }


    /**
     * @return 返回一个
     * @throws ByteBufException
     */
    public synchronized int read() throws ByteBufException {
        if (size < 1) {
            throw new ByteBufException("元素个数为:" + size);
        }
        int val = buf[0];
        System.arraycopy(buf, 1, buf, 0, buf.length - 1);
        size--;
        return val & 0xff;
    }


    public synchronized short readShortNoRemove(int startIndex) {
        if (size < startIndex + 1) {
            throw new ArrayIndexOutOfBoundsException(startIndex + 1);
        }
        short val = 0;
        int b0 = buf[startIndex];
        int b1 = buf[startIndex + 1];
        short s0 = (short) (b0 & 0xff);
        short s1 = (short) (b1 & 0xff);
        val = (short) ((s0 << 8) + (s1 << 0));
        return val;

    }

    public synchronized int readUnsignedByte(int position) {
        if (position > size) {
            throw new ArrayIndexOutOfBoundsException(position);
        }
        return buf[position] & 0xff;
    }

    /**
     * 返回一个有符号的byte
     */
    public synchronized byte readByte() throws ByteBufException {
        return (byte) read();
    }

    public synchronized String hex() {
        return Hex.encodeHexStr(buf, size);
    }


    public class ByteBufException extends Exception {
        String msg;

        public ByteBufException(String msg) {
            this.msg = msg;
        }

        @Override
        public String getMessage() {
            return msg;
        }

    }


    /**
     * 读取四个字节的int 高位在前,低位在后
     */
    public final synchronized int readInt() throws ByteBufException {
        if (size < 4) {
            throw new ByteBufException("readInt but 元素个数为:" + size);
        }
        int b0 = read();
        int b1 = read();
        int b2 = read();
        int b3 = read();
        int val = b0 << 24 | b1 << 16 | b2 << 8 | b3 & 0xff;
        return val;

    }

    /**
     * 读取四个字节的float
     */
    public final synchronized float readFloat() throws ByteBufException {
        if (size < 4) {
            throw new ByteBufException("readFloat but 元素个数为:" + size);
        }
        int b0 = read();
        int b1 = read();
        int b2 = read();
        int b3 = read();
        int val;
        val = b3;
        val &= 0xff;
        val |= ((long) b2 << 8);
        val &= 0xffff;
        val |= ((long) b1 << 16);
        val &= 0xffffff;
        val |= ((long) b0 << 24);
        return Float.intBitsToFloat(val);
    }

    /**
     * 读取有符号short
     */
    public final synchronized short readShort() throws ByteBufException {
        short val = 0;
        int b0 = read();
        int b1 = read();
        short s0 = (short) (b0 & 0xff);
        short s1 = (short) (b1 & 0xff);
        val = (short) ((s0 << 8) + (s1 << 0));
        return val;
    }

    /**
     * 读取一个无符号字节
     */
    public final synchronized int readUnsignedByte() throws ByteBufException {
        int ch0 = read();
        return ch0 & 0xff;

    }

    /**
     * 读取无符号short
     */
    public final synchronized int readUnsignedShort() throws ByteBufException {
        int ch1 = read();
        int ch2 = read();
        return (ch1 << 8) + (ch2 << 0);
    }

    /**
     * 读取一个long类型
     */
    public final synchronized long readLong() throws ByteBufException {
        return (((long) read() << 56) +
                ((long) (read() & 0xff) << 48) +
                ((long) (read() & 0xff) << 40) +
                ((long) (read() & 0xff) << 32) +
                ((long) (read() & 0xff) << 24) +
                ((read() & 0xff) << 16) +
                ((read() & 0xff) << 8) +
                ((read() & 0xff) << 0));
    }

    /**
     * 返回一个ascill码
     */
    public final synchronized char readAscill() throws ByteBufException {
        return (char) (read());
    }

    /**
     * 返回一个两字节组成的char
     */
    public final synchronized char readChar() throws ByteBufException {
        int ch1 = read();
        int ch2 = read();
        return (char) ((ch1 << 8) + (ch2 << 0));
    }

    public final synchronized double readDouble() throws ByteBufException {
        return Double.longBitsToDouble(readLong());
    }

    /**
     * 按照长度读取一个字符串
     */
    public final synchronized String readString(int len) throws ByteBufException {
        byte[] bs = new byte[len];
        for (int index = 0; index < bs.length; index++) {
            bs[index] = (byte) read();
        }
        return new String(bs);
    }


    public final synchronized String getAllString() {
        String val = null;
        try {
             val = new String(getByteArray(),"utf-8");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return val;
    }

    public final synchronized void appendByte(int val) {
        int wantSize = size + 1;
        //如果总共的元素个数超过了总容量*容量因数 就进行拓展
        if (wantSize > capacity * capacityFactor) {
            grow(wantSize);
        }
        buf[size++] = (byte) val;
    }

    public final synchronized void appendDouble(double val) {
        long lbit = Double.doubleToLongBits(val);
        byte[] b = new byte[8];
        for (int i = 0; i < 8; i++) {
            b[i] = (byte) (lbit >> (64 - (i + 1) * 8));
        }
        int len = b.length;
        // 建立一个与源数组元素类型相同的数组
        byte[] dest = new byte[len];
        // 为了防止修改源数组,将源数组拷贝一份副本
        System.arraycopy(b, 0, dest, 0, len);
        appendByteArray(dest);

    }


    public final synchronized void appendShort(int val) {
        byte[] bs = new byte[2];
        bs[0] = (byte) (val >> 8 & 0xff);
        bs[1] = (byte) (val & 0xff);
        appendByteArray(bs);
    }

    public final synchronized void appendFloat(float val) {
        // 把float转换为byte[]
        int fbit = Float.floatToIntBits(val);

        byte[] b = new byte[4];
        for (int i = 0; i < 4; i++) {
            b[i] = (byte) (fbit >> (24 - i * 8));
        }


        int len = b.length;
        // 建立一个与源数组元素类型相同的数组
        byte[] dest = new byte[len];
        // 为了防止修改源数组,将源数组拷贝一份副本
        System.arraycopy(b, 0, dest, 0, len);
        appendByteArray(dest);
    }

    public final synchronized void appendInt(int val) {
        byte[] b = new byte[4];
        for (int i = 0; i < 4; i++) {
            b[i] = (byte) (val >> (24 - i * 8));
        }
        // 翻转数组
        int len = b.length;
        // 建立一个与源数组元素类型相同的数组
        byte[] dest = new byte[len];
        // 为了防止修改源数组,将源数组拷贝一份副本
        System.arraycopy(b, 0, dest, 0, len);
        appendByteArray(dest);
    }

    /**
     * 符合十六进制的字符串,未做格式校验,请谨慎使用
     *
     * @param hex
     */
    public final synchronized void appendHexString(String hex) {
        byte[] bytes = hexStringToByteArray(hex);
        appendByteArray(bytes);
    }

    /**
     * 16进制表示的字符串转换为字节数组
     *
     * @param s 16进制表示的字符串
     * @return byte[] 字节数组
     */
    private final byte[] hexStringToByteArray(String s) {
        String s1 = s.replaceAll("[ ]*", "");
        System.out.println("sl = " + s1);
        int len = s1.length();
        byte[] b = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 两位一组,表示一个字节,把这样表示的16进制字符串,还原成一个字节
            b[i / 2] = (byte) ((Character.digit(s1.charAt(i), 16) << 4) + Character
                    .digit(s1.charAt(i + 1), 16));
        }
        return b;
    }


}

猜你喜欢

转载自blog.csdn.net/weixin_37699212/article/details/82805421