zlib官网:zlib Home Site
zlib光网可以下载源码,也可以通过github下载源码:https://github.com/madler/zlib/tree/develop
下载后目录如下:
使用visual studio编译需要进入contrib\vstudio目录,里面有不同版本的vs解决方案,根据自己的visual studio版本选择即可:
编译库很简单,zlibvc.vcxprocj是库,编译产出文件是zlibwapi.lib和zlibwapi.dll,可以自己改成静态库版本。
使用库,有个小坑,自己编写了一个demo,库的确引入了,头文件只需要zlib.h和zconf.h两个文件,但是编译的时候,提示找不到uncompress和compress符号,对比zlib的demo【testzlibdll.vcxproj】发现工程里面定义了宏:ZLIB_WINAPI,自己的项目加上这个宏定义之后顺利编译通过。
简单demo
#include <stdio.h>
#include "include/zlib.h"
// 传入二进制数据的文件路径,没有字符串因为二进制数据不方便通过命令行传入
void testUnCompress(const char* filePath) {
FILE* fp = NULL;
int fileSize = 0;
unsigned char* fileBuffer = NULL;
unsigned char* outBuffer = NULL;
uLongf outBufferSize = 0;
int ret = 0;
ret = fopen_s(&fp, filePath, "rb");
if (!fp) {
printf("fopen %s fialed, error:%d\r\n", filePath, ret);
return;
}
fseek(fp, 0, SEEK_END);
fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (fileSize > 10 * 1024 * 1024) {
printf("too big test file");
return;
}
fileBuffer = new unsigned char[fileSize];
if (!fileBuffer) {
printf("new buffer failed for file:%d", fileSize);
return;
}
ret = fread(fileBuffer, 1, fileSize, fp);
if (ret != fileSize) {
printf("read failed, %d!=%d", ret, fileSize);
return;
}
printf("try uncompress:0x%02x 0x%02x ... 0x%02x 0x%02x \r\n",
fileBuffer[0], fileBuffer[1], fileBuffer[fileSize-2], fileBuffer[fileSize-1]);
// 以为不传入内存,接口会返回Z_MEM_ERROR结果并没有
// 需要自己估计一个内存大小,根据zlib官方解释,压缩的负责人需要通过某个途径告诉解压缩的负责人,压缩之前数据量多大。
outBuffer = new unsigned char[800];
outBufferSize = 800;
// 需要添加宏ZLIB_WINAPI否则提示找不到符号
ret = uncompress(outBuffer, &outBufferSize, fileBuffer, fileSize);
if (Z_MEM_ERROR == ret) {
if (outBufferSize > 0) {
// 并不会走到这个逻辑
printf("need out buffer size:%lu\r\n", outBufferSize);
if (outBufferSize > 100 * 1024 * 1024) {
printf("buffer need too big, return\r\n");
return;
}
outBuffer = new unsigned char[outBufferSize];
ret = uncompress(outBuffer, &outBufferSize, fileBuffer, fileSize);
if (Z_OK == ret) {
printf("test uncompress success\r\n");
}
else {
printf("test uncompress failed:%d\r\n", ret);
return;
}
}
else {
printf("do not now how much buffer need\r\n");
return;
}
}
else {
printf("first test uncompress return %d,outBufferSize=%d\r\n", ret, outBufferSize);
}
printf("test uncompress get data:\r\n%s\r\n", outBuffer);
}
// 压缩字符串,传入字符串,字符串有空格的话,命令行里面记得加双引号
void testCompress(const char* str) {
int ret = 0;
unsigned char* outBuffer = NULL;
uLongf outSize = 0;
// 可以通过compressBound获取压缩后大概多大,
outBuffer = new unsigned char[60];
outSize = 60;
printf("try to comprss:%s\r\n", str);
printf("len:%d\r\n", strlen(str));
// compress是compress2的默认压缩级别
// 此处传入的级别是9,可以使用其他级别。
ret = compress2(outBuffer, &outSize, (const unsigned char*)str, strlen(str), 9);
if (Z_MEM_ERROR == ret) {
if (outSize > 0) {
// 以为传入的目标大小不够时会走这个逻辑,其实并不会
printf("need out buffer size:%lu\r\n", outSize);
if (outSize > 1024) {
printf("buffer need too big, return\r\n");
return;
}
outBuffer = new unsigned char[outSize];
ret = compress2(outBuffer, &outSize, (const unsigned char*)str, strlen(str), 9);
if (Z_OK == ret) {
printf("test uncompress success:\r\n%s\r\n", outBuffer);
}
else {
printf("test uncompress failed:%d\r\n", ret);
return;
}
}
else {
printf("do not now how much buffer need\r\n");
return;
}
}
else {
printf("first test uncompress return %d\r\n", ret);
}
// 打印压缩后的二进制数据,只是测试而已,不要太认真
for (int i = 0; i < outSize; ++i) {
printf("0x%02x ", outBuffer[i]);
}
printf("\r\n");
}
坑:压缩代码不能提前知道数据被压缩后的大小,解压缩代码不能提前知道压缩前的大小。
解决方案:压缩前通过compressBound获取一个大概的压缩后的大小,解压缩的时候要求传入压缩前的大小。不然就只能通过代码一点点尝试了