(int32/uint32)整数压缩与解压缩算法

对网络包进行压缩可以减少网络带宽,提高传输效率, 很多时候一些报文中包含一些无符号整数,比如报文头中的长度信息.正常情况下一个无符号整数占用32位

0x0000 0000 到 0xFFFF FFFF .

由于一个无符号整数始终占据着4字节内存,就算是1也会占据着4个字节,其实只要1字节就可以保存了.(要想压缩整数,基本算法思想是压缩在4字节之内也就是1,2,3,4.

把无符号整数进行逻辑分段:

0x00 ~ 0xFF 0~255 1Byte 0x100 ~ 0xFFFF 256~65535 2Byte 0x10000 ~ 0xFFFFFF 65536~16777215 3Byte 0x1000000 ~ 0xFFFFFFFF 16777216~4294967295 4Byt (无意义)

通过上面可以大致看出1~4字节的逻辑分层.把无符号整数进行压缩在一个字符数组内,定义一个char buf[4];

当在0x00~0xFF之间时:

因为是只有1个字节只要保存在buf[0] 这个字符内。


当在0x100~0xFFFF之间时:

这个范围是2个字节,把前8位保存于数组buf[0]内,后8位保存于数组buf[1]内 。通过位操作即可。


当在0x100~0xFFFFFF之间时也类似。


当在0x1000000 ~ 0xFFFFFFFF这个范围不进行压缩。因为必须占用4个字节,所以没什么意义。

下面看下压缩代码:

bool cb_compress(unsigned int data, char* buf, unsigned int& len) { if (data <= 0xFF) { buf[0] = (char)data; len = 1; } else if (data <= 0xFFFF) { buf[0] = (char)((data & 0xFF00 )>> 8); buf[1] = (char)((data & 0x00FF)); len = 2; } else if (data <= 0xFFFFFF) { buf[0] = (char)((data & 0x00FF0000) >> 16); buf[1] = (char)((data & 0x0000FF00) >> 8); buf[2] = (char)(data & 0x000000FF); len = 3; } else { cout<<"Invaild Data"<<endl; } return TRUE; }

对压缩过的数据进行解压缩,只要和压缩操作相反就可以了。不过要特别注意符号位的问题!

bool cb_unCompress(char* buf, int len, unsigned int& data) { if (3 == len) { data = (unsigned int)(((buf[0]<<16) & 0x00FFFFFF) | ((buf[1]<<8) & 0x00FFFF) | (buf[2] & 0x0000FF) & 0x00FFFFFF); } else if (2 == len) { data = (unsigned int)((((buf[0]<<8) & 0x00FFFF)) | (buf[1] & 0x0000FF) & 0x00FFFF); //0x00FF } else if (1 == len){ data = (unsigned int)buf[0] & 0x000000FF; } else { cout<<"unCompress Error"<<endl; } return TRUE; }

压缩图示:


如果你使用的Python,你可以从struct.pack这个方法进行入手。

比如:压缩2个字节:

buf = (c_char * 2)() buf[0] = struct .pack("B", (data & 0xFF00)>>8); buf[1] = struct.pack("B", data & 0x00FF);

解压缩进行upack即可:

_data0 = stuct.unpack("B" , data[0])[0] _data1 = struct.unpack("B", data[1])[0] unpack_data = _data0<<8 | _data1 & 0x00FF



还有种算法是通过每7位一保存。前面1位为符号位(非有符号的符号位,而是如果为0表示后面没有数据,1表示有数据)

bool cb_compress(unsigned int data, char *buf, unsigned int &len) { len = 0; for (int i=4; i>=0; i--) { char c; c = (data >> (i*7)) & 0x7f; //小于128的直接为本数 if (c == 0x00 && !len) { //通过不停左移查看几位数据 continue; } //1 byte if (i == 0) { c &= 0x7f; } else //0x80为掩码 { c |= 0x80; } buf[len] = c; len++; } //Invaild Data if (!len) { len++; buf[0] = 0; } return TRUE; }

如果检查为1 表示后面7位需要和下面一段数据进行拼接,0表示后面7位为最后7位。 所以可能压缩后位1~5字节内。

解压缩:

bool cb_unCompress(char *buf, int len, unsigned int &i) { i = 0; for (int index = 0; index < (int)len; index++) { char c = *(buf + index); //取出压缩数据 i = i << 7; c &= 0x7f; i |= c; //多于1位进行左移解压缩 } return TRUE; }


Python实现压缩与解压缩:( 本段程序,参考http://www.cnblogs.com/AndersLiu/archive/2010/02/09/compressed-integer-in-metadata.html)

def Compress(self, data): if data <= 0x7F: bytes_1Arr = (c_char * 1)() bytes_1Arr = struct.pack("B", data); return bytes_1Arr elif data <= 0x3FFF: bytes_2Arr = (c_char * 2)() bytes_2Arr[0] = struct.pack("B", (data & 0xFF00)>>8 | 0x80); bytes_2Arr[1] = struct.pack("B", data & 0x00FF); return bytes_2Arr elif data <= 0xffff: bytes_3Arr = (c_char * 4)() bytes_3Arr[0] = struct.pack("B", (data & 0xFF000000)>>24 | 0xC0); bytes_3Arr[1] = struct.pack("B", (data & 0x00FF0000)>>16); bytes_3Arr[2] = struct.pack("B", (data & 0x0000FF00)>>8); bytes_3Arr[3] = struct.pack("B", (data & 0x000000FF)); return bytes_3Arr else: print "Invaild Data"
def unCompress(self, data): _len = len(data) if _len == 1: return struct.unpack("B", data[0]) elif _len == 2: _data0 = struct.unpack("B", data[0]) _data1 = struct.unpack("B", data[1]) return ((_data0[0] & 0x3F)<<8 | _data1[0]) & 0x00FF elif _len == 4: _data0 = struct.unpack("B", data[0])[0] _data1 = struct.unpack("B", data[1])[0] _data2 = struct.unpack("B", data[2])[0] _data3 = struct.unpack("B", data[3])[0] return ((_data0 & 0x1F)<<24 | _data1<<16 | _data2<<8 | _data3); else: print "unCompress Error!"另外需要注意的是 Python返回后的是个元祖 需要 用 .value来取值

图示:

-> 1000 0001 | 0000 0000

关于压缩和解压缩(Include Integer) 更多信息可以读下面一篇文章:

http://www.cs.tut.fi/~albert/Dev/pucrunch/packing.html




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值