zlib是一个免费、通用、无损的数据压缩库,而且还是跨平台的。zlib具有同winzip和winrar等商业软件相比毫不逊色的压缩率,已经成功应用在诸如MySQL、Java、3DMax、甚至是微软的DirectX等大型的系统中。目前Z1ib的最新版本是1.2.8。
zlib的最新版本可以在http://www.zlib.net下载,下载后只需用Visual C++编译该工程即可得到开发所需的zlib.h、zconf.h、 zlib.lib和zlib.dll等文件。
本文主要研究zlib的内存数据压缩方法。zlib提供了一套 in-memory 压缩和解压函数,并能检测解压出来的数据的完整性(integrity)。zlib 也支持读写 gzip (.gz) 格式的文件(注意:zlib函式库本身不能创建一个gzip文件,但是它相当轻松的通过把压缩数据写入到一个有gzip文件头的文件中)。下面介绍两个最有用的函数:compress 和 uncompress。
1、compress函数
声明如下:
/* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. This function can be used to compress a whole file at once if the input file is mmap'ed. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
若compress 若成功,则返回 Z_OK;若没有足够内存,则返回 Z_MEM_ERROR;若输出缓冲区不够大,则返回 Z_BUF_ERROR。
2、uncompress函数
声明如下:
/* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the compressed buffer. This function can be used to decompress a whole file at once if the input file is mmap'ed. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. */ int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);uncompress 函数将 source 缓冲区的内容解压缩到 dest 缓冲区。sourceLen 是 source 缓冲区的大小(以字节计)。注意函数的第二个参数 destLen 是传址调用。当调用函数时,destLen 表示 dest 缓冲区的大小, dest 缓冲区要足以容下解压后的数据。在进行解压缩时,需要提前知道被压缩的数据解压出来会有多大。这就要求在进行压缩之前,保存原始数据的大小(也就是解压后的数据的大小)。这不是 zlib 函数库的功能,需要我们做额外的工作。当函数退出后, destLen 是解压出来的数据的实际大小。
3、使用示例
// testzlib.cpp 简单测试 zlib 的压缩功能 #include <cstring> #include <cstdlib> #include <iostream> #include "zlib.h" using namespace std; int main() { int err; Byte compr[200], uncompr[200]; // big enough uLong comprLen, uncomprLen; const char* hello = "12345678901234567890123456789012345678901234567890"; uLong len = strlen(hello) + 1; comprLen = sizeof(compr) / sizeof(compr[0]); err = compress(compr, &comprLen, (const Bytef*)hello, len); if (err != Z_OK) { cerr << "compess error: " << err << '\n'; exit(1); } cout << "orignal size: " << len << " , compressed size : " << comprLen << '\n'; strcpy((char*)uncompr, "garbage"); err = uncompress(uncompr, &uncomprLen, compr, comprLen); if (err != Z_OK) { cerr << "uncompess error: " << err << '\n'; exit(1); } cout << "orignal size: " << len << " , uncompressed size : " << uncomprLen << '\n'; if (strcmp((char*)uncompr, hello)) { cerr << "BAD uncompress!!!\n"; exit(1); } else { cout << "uncompress() succeed: \n" << (char *)uncompr; } }编译执行这个程序,输出结果如下:
D:\libpng\zlib-1.1.4>bcc32 testzlib.cpp zlib.lib D:\libpng\zlib-1.1.4>testzlib orignal size: 51 , compressed size : 22 orignal size: 51 , uncompressed size : 51 uncompress() succeed: 12345678901234567890123456789012345678901234567890
4、函数使用说明
5、应用场景
(1)节约空间
当需要将一个很占内存的变量写入文件以节省内存时,可以先压缩一下,然后写入文件,当需要使用时再从文件中读出,然后解压缩,以便节省IO时间。此外,有些情况可能还要序列化一下,当要压缩的内存不是一段连续的内存的时候。
(2)节约网络流量
待发送的数据包比较大,且网络流量有限时,这两个函数也能派上用场。发送数据包前,先将数据包buffer压缩一下;接收方收到数据后再解压一下,这样接收方就能得到原始数据了。
参考文章:
1、http://blog.csdn.net/turingo/article/details/8148264
2、http://www.cnblogs.com/fairycao/archive/2009/12/09/1620414.html