马上:纸币互动,智能笔数据点压缩
对接一款智能笔,笔的数据是通过蓝牙传给app, 但是笔的笔迹点数量很多,网络传输用json就不恰当。所以一番调研才起二进制压缩点(数字压缩基本原理)
基本数据
class Dot implements Serializable {
public int Counter;
public int SectionID;
public int OwnerID;
public int BookID;
public int PageID;
public long timelong;
public int x;
public int y;
public int fx;
public int fy;
public int force;
public int angle;
public Dot.DotType type;
public float ab_x;
public float ab_y;
public int color = -16777216;
}
上面除了timelong, 其它数据都可以通过一个字节来装载
Dot vPenDot = list.get(i);
int index = i * DOT_BYTE_LENGTH;
bytes[index] = (byte) vPenDot.Counter;
bytes[index + 1] = (byte) vPenDot.BookID;
bytes[index + 2] = (byte) vPenDot.SectionID;
bytes[index + 3] = (byte) vPenDot.OwnerID;
bytes[index + 4] = (byte) vPenDot.angle;
bytes[index + 5] = (byte) vPenDot.force;
bytes[index + 6] = (byte) vPenDot.x;
bytes[index + 7] = (byte) vPenDot.y;
bytes[index + 8] = (byte) vPenDot.fx;
bytes[index + 9] = (byte) vPenDot.fy;
//枚举类转为数字存储
bytes[index + 10] = (byte) vPenDot.type.ordinal();
同样long型用8个字节存储. 要用byte 来装的话
long timeLong = vPenDot.timelong;
//直接赋值
bytes[index + 11] = (byte) (timeLong >> 56);
bytes[index + 12] = (byte) (timeLong >> 48);
bytes[index + 13] = (byte) (timeLong >> 40);
bytes[index + 14] = (byte) (timeLong >> 32);
bytes[index + 15] = (byte) (timeLong >> 24);
bytes[index + 16] = (byte) (timeLong >> 16);
bytes[index + 17] = (byte) (timeLong >> 8);
bytes[index + 18] = (byte) timeLong;
同样还原数据点,就反之
Dot dot = new Dot();
dot.Counter = (dotsBytes[index] & FF);
dot.BookID = (dotsBytes[index + 1] & FF);
dot.PageID = (dotsBytes[index + 2] & FF);
dot.SectionID = (dotsBytes[index + 3] & FF);
dot.OwnerID = (dotsBytes[index + 4] & FF);
dot.angle = (dotsBytes[index + 5] & FF);
dot.force = (dotsBytes[index + 6] & FF);
dot.x = (dotsBytes[index + 7] & FF);
dot.y = (dotsBytes[index + 8] & FF);
dot.fx = (dotsBytes[index + 9] & FF);
dot.fy = (dotsBytes[index + 10] & FF);
dot.type = (getType(dotsBytes[index + 11] & FF));
dot.ab_x = (Dot.toAbsolute(dot.x, dot.fx));
dot.ab_y = Dot.toAbsolute(dot.y, dot.fy);
long timeLong = 0;
timeLong = timeLong + ((long) (dotsBytes[index + 12] & FF) << 56);
timeLong = timeLong + ((long) (dotsBytes[index + 13] & FF) << 48);
timeLong = timeLong + ((long) (dotsBytes[index + 14] & FF) << 40);
timeLong = timeLong + ((long) (dotsBytes[index + 15] & FF) << 32);
timeLong = timeLong + ((long) (dotsBytes[index + 16] & FF) << 24);
timeLong = timeLong + ((long) (dotsBytes[index + 17] & FF) << 16);
timeLong = timeLong + ((long) (dotsBytes[index + 18] & FF) << 8);
timeLong = timeLong + ((long) (dotsBytes[index + 19] & FF));
我们会发现,long 这家伙居然要占8b, 我灵机一动(时间戳是有规律的)。
byte bytes[] = new byte[8];
// long timeLong = System.currentTimeMillis();
long timeLong = 33198110775000L; //3022-01-03 17:26:15 这个long 也只需要6byte 就
// long timeLong = 33198110775000L/1000;
System.out.println(timeLong);
//直接赋值
// bytes[0] = (byte) (timeLong >> 56);
// bytes[1] = (byte) (timeLong >> 48);
bytes[2] = (byte) (timeLong >> 40);
bytes[3] = (byte) (timeLong >> 32);
bytes[4] = (byte) (timeLong >> 24);
bytes[5] = (byte) (timeLong >> 16);
bytes[6] = (byte) (timeLong >> 8);
bytes[7] = (byte) timeLong;
for (byte aByte : bytes) {
System.out.println(aByte);
}
bytes 前面2位是0,没错long 数据范围-9223372036854775808~9223372036854775807,所以又能少2位了,如果记录单位为秒的,少3位。
long now = System.currentTimeMillis();
System.out.println(now);
long passTime = 1641223315620L;
long cipherText = (now ^ passTime);
System.out.println(cipherText);
System.out.println(passTime ^ cipherText);
cipherText 是距离某个过去时间多少毫秒,能反^ 得出真正的毫秒数
1000606024365*10=1827387392 10年时间 ,
147122892800 100年
数越小,所用到的byte 越少