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