(int32/uint32)整数压缩与解压缩算法---VB编码

对网络包进行压缩可以减少网络带宽,提高传输效率, 很多时候一些报文中包含一些无符号整数,比如报文头中的长度信息.正常情况下一个无符号整数占用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个字节,所以没什么意义。

下面看下压缩代码:

 

// 输入无符号整数data,压缩到1-4个字节后存入buf,返回压缩后的字节数
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 {
       // 超过 0xFFFFFF 的不进行压缩
       cout << "Invaild Data" << endl; 
    } 
    return TRUE; 
}

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

// 输入字节数组和字节数,输出一个整数data 
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; 
    // 32bit分成5段,每段7bit
    for (int i = 4; i >= 0; --i) { 
        //得到第i段的数值
        char c = (data >> (i*7)) & 0x7f; 
        if (c == 0x00 && !len) {
            //最左的几段值为0,不保存
            continue; 
        } 
        
        //最右段
        if (i == 0) { 
            c &= 0x7f; 
        } else {//并非最右段,首bit标记为1表示后面有数据 
            c |= 0x80; 
        } 
        buf[len] = c; 
        len++; 
    } 
    
    //Invaild Data 
    if (!len) { 
        len++; 
        buf[0] = 0; 
    } 
    return TRUE; 
}
// 评:上述压缩过程如果知道最终len是多少,那么只需要把最左非0段的首位bit置1即可,
// 在字符流的解码过程中,只要遇到了首位bit为1的段就知道是一个新的数据开始了。

 

如果检查为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; 
}

评:当把一个整数的bit串分成5段后,最左段是不够8bit的,那么对于int型的整数,可以把它当做uint型整数来压缩和解压缩。

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

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于计算机专业的学生而言,参加各类比赛能够带来多方面的益处,具体包括但不限于以下几点: 技能提升: 参与比赛促使学生深入学习和掌握计算机领域的专业知识与技能,如编程语言、算法设计、软件工程、网络安全等。 比赛通常涉及实际问题的解决,有助于将理论知识应用于实践中,增强问题解决能力。 实践经验: 大多数比赛都要求参赛者设计并实现解决方案,这提供了宝贵的动手操作机会,有助于积累项目经验。 实践经验对于计算机专业的学生尤为重要,因为雇主往往更青睐有实际项目背景的候选人。 团队合作: 许多比赛鼓励团队协作,这有助于培养学生的团队精神、沟通技巧和领导能力。 团队合作还能促进学生之间的知识共享和思维碰撞,有助于形成更全面的解决方案。 职业发展: 获奖经历可以显著增强简历的吸引力,为求职或继续深造提供有力支持。 某些比赛可能直接与企业合作,提供实习、工作机会或奖学金,为学生的职业生涯打开更多门路。 网络拓展: 比赛是结识同行业人才的好机会,可以帮助学生建立行业联系,这对于未来的职业发展非常重要。 奖金与荣誉: 许多比赛提供奖金或奖品,这不仅能给予学生经济上的奖励,还能增强其成就感和自信心。 荣誉证书或奖状可以证明学生的成就,对个人品牌建设有积极作用。 创新与研究: 参加比赛可以激发学生的创新思维,推动科研项目的开展,有时甚至能促成学术论文的发表。 个人成长: 在准备和参加比赛的过程中,学生将面临压力与挑战,这有助于培养良好的心理素质和抗压能力。 自我挑战和克服困难的经历对个人成长有着深远的影响。 综上所述,参加计算机领域的比赛对于学生来说是一个全面发展的平台,不仅可以提升专业技能,还能增强团队协作、沟通、解决问题的能力,并为未来的职业生涯奠定坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值