1. 程式人生 > >ByteBuf 一個用於在通訊中的資料解析傳輸組裝的自定義容器類

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;
    }


}