从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; }
压缩图示:
比如:压缩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