前几天和服务端同事联调TCP传输压缩后的Json串,遇到了 GZIP压缩问题。
需要把原来使用的的压缩算法和后端统一,现在来总结一下。
【注意】 这里就以Windows的Debug环境为例,Release版也是一样,只需更改配置编译就好。
代码演示中不未涉及文件序列化问题。文件(文件夹)压缩问题,可以参考zip压缩文章Zip压缩解压缩
1.下载zlib源码及工程文件:
https://www.zlib.net/
2.拿到源码包解压看看
3.打开目录zlib-1.2.11\contrib\vstudio\vc12下的解决方案:
一堆错误,编译失败:
解决方案:https://www.cnblogs.com/lzhu/p/9602674.html
我在示例中使用的VS2013编译的VC12的示例解决方案,报错。得把这六个工程都修复下:
编译成功:
4.编译成功,得到库文件:
打开工程目录,从x86\ZlibDllDebug下拿到库文件zlibwapi.lib和zlibwapi.dll,再从压缩包根目录zlib-1.2.11\下拿到zlib.h、zconf.h、zutil.h三个头文件
5.新建测试工程,并添加zlib目录,把拿到的lib文件以及三个头文件文件放进去,并把dll文件放到debug目录下。
6.demo工程属性-链接器-常规-附加依赖项-…/zlib/debug/zlibwapi.lib;
7.添加工具类CGZipAssistant到工程里面:
/*
GZipAssisant.h
*/
#pragma once
class GZipAssistant
{
public:
GZipAssistant();
~GZipAssistant();
public:
int Compress(const char *src, int srcLen, char *dest, int destLen);
int Decompress(const char *src, int srcLen, const char *dst, int dstLen);
static GZipAssistant* GetInstance()
{
static GZipAssistant ins;
return &ins;
}
};
GZipAssistant* GetGZipAssistant();
/*
GZipAssisant.cpp
*/
#include "stdafx.h"
#include "../zlib/zlib.h"
#include "GZipAssisant.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
GZipAssistant::GZipAssistant()
{
}
GZipAssistant::~GZipAssistant()
{
}
int GZipAssistant::Compress(const char *src, int srcLen, char *dest, int destLen)
{
z_stream c_stream;
int err = 0;
int windowBits = 15;
int GZIP_ENCODING = 16;
if (src && srcLen > 0)
{
c_stream.zalloc = (alloc_func)0;
c_stream.zfree = (free_func)0;
c_stream.opaque = (voidpf)0;
if (deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
windowBits | GZIP_ENCODING, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;
c_stream.next_in = (Bytef *)src;
c_stream.avail_in = srcLen;
c_stream.next_out = (Bytef *)dest;
c_stream.avail_out = destLen;
while (c_stream.avail_in != 0 && c_stream.total_out < destLen)
{
if (deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;
}
if (c_stream.avail_in != 0) return c_stream.avail_in;
for (;;) {
if ((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;
if (err != Z_OK) return -1;
}
if (deflateEnd(&c_stream) != Z_OK) return -1;
return c_stream.total_out;
}
return -1;
}
int GZipAssistant::Decompress(const char *src, int srcLen, const char *dst, int dstLen) {
z_stream strm;
strm.zalloc = NULL;
strm.zfree = NULL;
strm.opaque = NULL;
strm.avail_in = srcLen;
strm.avail_out = dstLen;
strm.next_in = (Bytef *)src;
strm.next_out = (Bytef *)dst;
int err = -1, ret = -1;
err = inflateInit2(&strm, MAX_WBITS + 16);
if (err == Z_OK) {
err = inflate(&strm, Z_FINISH);
if (err == Z_STREAM_END) {
ret = strm.total_out;
}
else {
inflateEnd(&strm);
return err;
}
}
else {
inflateEnd(&strm);
return err;
}
inflateEnd(&strm);
return err;
}
GZipAssistant* GetGZipAssistant()
{
return GZipAssistant::GetInstance();
}
8.调用测试:
void CDemoDlg::OnBnClickedButtonGogogo()
{
//压缩:
const char* pSrc = "12312312313萨达萨达木alkjslngadaldn扩锁军,#¥@……@!#多绿蓑女所军副盘";
int nLenSrc = strlen(pSrc);
int nLenCompress = nLenSrc * 2;
char* pCompressed = new char[nLenCompress];
memset(pCompressed, 0, nLenCompress);
int nLencompressed = GetGZipAssistant()->Compress(pSrc, nLenSrc, pCompressed, nLenCompress);
if (nLencompressed <= 0)
{
MessageBox("Compress Failed");
}
//解压缩:
char* pDecompressed = new char[nLenSrc * 2];
memset(pDecompressed, 0, nLenSrc * 2);
int ret = GetGZipAssistant()->Decompress(pCompressed, nLencompressed, pDecompressed, nLenSrc * 2);
CString str = pDecompressed;
MessageBox(str);
delete[] pCompressed;
delete[] pDecompressed;
}
测试成功,Release版本的一样的套路,改改配置编译即可,亲测可行。
参考文章:
https://blog.csdn.net/moxiaomomo/article/details/52385837
https://www.cnblogs.com/lzhu/p/9602674.html