在做和硬件通信的项目的时候,通信的内容一般都是最基本的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;
}
}