zlib是zip压缩库,可以实现在程序里使用zip功能(而不用通过执行命令)。
通过在程序内部使用压缩可以减少写入到磁盘的数据量,虽然用命令行也能实现同样的功能,但是命令行只能用于完整文件,灵活度很低,也不够专业。
对于超大型数据文件,整个压缩解压缩也不是很合适,耗时耗空间,而程序或许只是需要其中的一小部分数据,如果数据是分块压缩的,则可以只解压少数数据块即可(如果是超大文件,拆分为小文件经常是不可行的)。
头文件:zlib.h
链接参数:-lz
用法相当简单:
ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen,
int level));
ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
const Bytef *source, uLong sourceLen));
就是这一对函数,level是压缩级别,0-9,越大压缩比越高,耗时也越长,默认级别是Z_DEFAULT_COMPRESSION,值是-1。
参数意思很明显。不过要注意的是,参数是内存区,而不是字符串。对字符串压缩时一定要说明是否包含了字符串结束符。strlen是不包括结束符的。
由于这是C风格接口,在C++里用包装一下比较好:
//这里还需要一些别的头文件
#include <zlib.h>
//数据压缩,压缩后数据自带解压缩以后长度
class CmyZip
{
public:
typedef unsigned long T_LEN;
//默认压缩级别
static bool Compress(char const * src, long srclen, CBuffer & output)
{
return Compress2(src, srclen, output, Z_DEFAULT_COMPRESSION);
}
//level 0-9 越大压缩率越高耗时越长
static bool Compress2(char const * src, T_LEN srclen, CBuffer & output, int level)
{
if (Z_DEFAULT_COMPRESSION == level);
else if (level < 0)level = 0;
else if (level > 9)level = 9;
else;
if (!output.reserve(compressBound(srclen) + sizeof(T_LEN)))
{
cout << "内存不足" << endi;
return false;
}
T_LEN len = output.capacity() - sizeof(T_LEN);
if (0 != compress2((unsigned char *)output.getbuffer() + sizeof(T_LEN), &len, (unsigned char *)src, srclen, level))
{
cout << "压缩失败" << endi;
return false;
}
T_LEN tmp = srclen;
memmove(output.getbuffer(), &tmp, sizeof(T_LEN));
output.setSize(sizeof(T_LEN) + len);
return true;
}
static bool UnCompress(char const * src, long srclen, CBuffer & output)
{
return _UnCompress(src, srclen, output, 1);
}
static bool _UnCompress(char const * src, long srclen, CBuffer & output, long buf_override)
{
T_LEN outsize;//压缩数据记录的解压缩后长度
memmove(&outsize, src, sizeof(T_LEN));
//cout << "记录的长度 " << outsize << endl;
if (0 == outsize)
{
output.setSize(0);
return true;
}
if (!output.reserve(outsize*buf_override))
{
cout << "内存不足" << endl;
return false;
}
unsigned long len = output.capacity();
int ret = uncompress((unsigned char *)output.getbuffer(), &len, (unsigned char *)src + sizeof(T_LEN), srclen - sizeof(T_LEN));
if (0 != ret)
{
if (Z_MEM_ERROR == ret)
{
cout << "解压缩失败 内存不足" << endl;
return false;
}
else if (Z_STREAM_ERROR == ret)
{
cout << "解压缩失败 level错误" << endl;
return false;
}
else if (Z_BUF_ERROR)
{
cout << "预设缓冲区不足 " << buf_override << " " << output.capacity() << " " << len << endi;
return _UnCompress(src, srclen, output, buf_override + 1);
}
else
{
cout << "解压缩失败 " << ret << endl;
return false;
}
}
if (len != outsize)
{
cout << "解压缩后长度与预期不一致 " << len << " " << outsize << endl;
return false;
}
output.setSize(len);
return true;
}
public:
static int CZip_test(int argc, char ** argv)
{
CEasyFile file;
CBuffer input;
CBuffer output;
CBuffer output2;
if (!file.ReadFile("文件名", input))
{
cout << "读文件失败" << endl;
return __LINE__;
}
if (!Compress(input.data(), input.size(), output))return __LINE__;
cout << input.size() << " " << output.size() << " " << (100 - output.size() * 100 / (input.size() ? input.size() : 1)) << "%" << endl;
if (!UnCompress(output.data(), output.size(), output2))return __LINE__;
cout << input.size() << " 解压缩后 " << output2.size() << endl;
if (!input.Compare(output2))return __LINE__;
for (long i = 0; i < 10; ++i)
{
if (!Compress2(input.data(), input.size(), output, i))return __LINE__;
cout << i << " " << input.size() << " " << output.size() << " " << (100 - output.size() * 100 / (input.size() ? input.size() : 1)) << "%" << endl;
}
return 0;
}
};
自带测试代码CZip_test。
代码相当简单,应该很容易看懂。用到的CEasyFile和CBuffer在我的其它文章里,功能也都很简单,一目了然。
(这里是结束)