c++字节压缩ByteData

1369次浏览

不管什么语言,一个变量至少要占1个字节(Byte),像char,bool,byte类型都是占1个字节,无符号的范围是0~255,有符号是-128~127。

在特殊情况下,当明确知道取值范围小于0~255,如0~3。这时候就会考虑怎么能再压缩内存。因为实际用不到1个字节,只用2个位(bit)即可,但只占2位的的类型是没有的。也许你会问,这省了这么点内存有什么用,即使使用int也没有什么大不了的。

对的,当只有一个两个的时候是不需要考虑,不过当面临大数组,成百上千,甚至上万个的时候,2个位跟1个字节相差了4倍,可以节省3/4的内存,压缩75%还是很可观的。

还有一种情况是数据库对二进制数据存储是有长度限制的,做服务器的话都知道用户数据上会有大量的0~1标记,这时候使用字节压缩1个用户就会节省87.5%的储存或内存。1w个,10w个用户那节省的可不是一点点了。

好了,不多说了,核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 读取函数
// @param data 存放二进制数据
// @param eachBit 每eachBit个bit位代表一个值
// @param index 获取指定索引位置的值
int get(const vector<unsigned char>& data, int eachBit, int index)
{
    int length = (int)data.size();
    int i = (index * eachBit) / 8;
    int  m = (index * eachBit) % 8;
    unsigned int mask = (0x01 << eachBit) - 0x01;
 
    if (i < 0 || i >= length || m < 0) {
        return 0;
    }
 
    return (data[i] & (mask << m)) >> m;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 设置函数
// @param data 存放二进制数据
// @param eachBit 每eachBit个bit位代表一个值
// @param index 指定要修改的索引位置
// @param value 新的值
void set(vector<unsigned char>& data, int eachBit, int index, int value)
{
    int length = (int)data.size();
    int i = (index * eachBit) / 8;
    int  m = (index * eachBit) % 8;
    unsigned int mask = (0x01 << eachBit) - 0x01;
 
    if (i < 0 || i >= length || m < 0) {
        return ;
    }
 
    mask = mask << m;
    value = value << m;
 
    // assert(value == (value & mask));
 
    data[i] = (data[i] & ~mask) | (value & mask);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 样例
#include<stdio.h>
#include<vector>
using namespace std;
 
int main()
{
    vector<unsigned char> data = {34, 2, 57, 123, 65, 93, 33};
 
    int a = get(data, 2, 8);
    set(data, 2, 8, a+1);
    int b = get(data, 2, 8);
 
    printf("a=%d b=%d \n", a, b);
}
1
2
// 打印结果
a=1 b=2

上面为通用算法代码,下面的是用c++对代码进行了包装,增加[]访问及迭代器的操作
点击下载:ByteData.zip