关于我们
技术分享
技术分享
zlib库内存压缩解压缩函数的C++便利性封装
zlib库内存压缩解压缩函数的C++便利性封装
2021-06-01
zlib是提供数据压缩用的函数库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表,普遍为许多软件所使用。
在使用zlib进行内存压缩解压缩的的时候主要用到的函数就是两个compress/uncompress。为了在C++中使用更方便,做一些便利性封装是非常必要的。
下面的代码中主要对zlib的内存压缩和解压缩进行了C++封装,出错以异常抛出。
因为zlib没办法估计解压缩后数据的长度,所以解压缩的时候,如果不知道源数据压缩之前的长度,就得估算一个长度来设置输出缓冲区大小,如果缓冲长度不足导致解压缩失败,就增大缓冲区再尝试直到解压缩成功。
/* * zlib_wrapper.h * * Created on: 2016年3月29日 * Author: guyadong */#ifndef INCLUDE_ZLIB_WRAPPER_H_#define INCLUDE_ZLIB_WRAPPER_H_#include <vector>#include "zlib.h"#define _DEF_STRING(x) #x#define DEF_TO_STRING(x) _DEF_STRING(x)#define SOURCE_AT __FILE__ ":" DEF_TO_STRING(__LINE__)#define ERROR_STR(msg) std::string(SOURCE_AT ":").append(msg)#define throw_except_if_msg(except,expression,msg) \ if(expression)\ throw except(ERROR_STR(msg));#define _CAS_ERROR_MSG_(ERR) case ERR:return #ERR;/* * 以sting形式返回错误信息 */inline std::string zlib_error_message(int err){ switch(err){ _CAS_ERROR_MSG_(Z_OK) _CAS_ERROR_MSG_(Z_MEM_ERROR) _CAS_ERROR_MSG_(Z_BUF_ERROR) _CAS_ERROR_MSG_(Z_STREAM_ERROR) }; return "unknow error"; }#undef _CAS_ERROR_MSG_/* zlib异常类 */class zlib_exception:public std::logic_error{ // 继承基类构造函数 using std::logic_error::logic_error; };/* * 调用zlib压缩数据 */inline std::vector<uint8_t> zlib_mem_compress (const void *source, size_t sourceLen){ throw_if(nullptr==source||0==sourceLen) std::vector<uint8_t> buffer(compressBound(sourceLen)); auto destLen=uLongf(buffer.size()); auto err=compress(buffer.data(),&destLen,reinterpret_cast<const Bytef *>(source),uLong(sourceLen)); throw_except_if_msg(zlib_exception,err!=Z_OK,zlib_error_message(err)) return std::vector<uint8_t>(buffer.data(),buffer.data()+destLen); }/* * 调用zlib压缩数组数据 */inline std::vector<uint8_t> zlib_mem_compress (const std::string &source){ return zlib_mem_compress(source.data(),source.size()); }/* * 调用zlib压缩数据 */template<typename T>inline std::vector<uint8_t> zlib_mem_compress (const std::vector<T> &source){ return zlib_mem_compress(source.data(),source.size()*sizeof(T)); }/* * 调用zlib压缩对象数据 */template<typename T>inline typename std::enable_if<std::is_class<T>::value,std::vector<uint8_t>>::type compress_obj (const T &source){ return zlib_mem_compress(std::addressof(source),sizeof(T)); }/* * 调用zlib解压缩数据 * uncompress_bound为压缩前的数据长度,如果不知道数据源长度设置为0 * */inline std::vector<uint8_t> zlib_mem_uncompress (const void *source, size_t sourceLen,size_t uncompress_bound=0){ throw_if(nullptr==source||0==sourceLen) //uncompress_bound为0时将缓冲区设置为sourceLen的8倍长度 if (!uncompress_bound) uncompress_bound = sourceLen << 3; for(;;){ std::vector<uint8_t> buffer(uncompress_bound); auto destLen=uLongf(buffer.size()); auto err=uncompress(buffer.data(),&destLen,reinterpret_cast<const Bytef *>(source),uLong(sourceLen)); if(Z_OK==err) return std::vector<uint8_t>(buffer.data(),buffer.data()+destLen); else if(Z_BUF_ERROR==err){ // 缓冲区不足 uncompress_bound<<=2;// 缓冲区放大4倍再尝试 continue; } // 其他错误抛出异常 throw zlib_exception(zlib_error_message(err)); } }/* * 调用zlib解压缩数据 * */inline std::string zlib_mem_uncompress (const std::string &source,size_t uncompress_bound=0){ auto un_data=zlib_mem_uncompress(source.data(),source.size(),uncompress_bound); return std::string((char*)un_data.data(),un_data.size()); }/* * 调用zlib解压缩数据 * */inline void zlib_mem_uncompress (void *dest,size_t *destLen,const void *source, size_t sourceLen){ throw_if(nullptr==source||0==sourceLen||nullptr==dest||nullptr==destLen||0==*destLen) auto len=uLongf(*destLen); auto err=uncompress(reinterpret_cast<Bytef *>(dest),&len,reinterpret_cast<const Bytef *>(source),uLong(sourceLen)); *destLen=size_t(len); throw_except_if_msg(zlib_exception,err!=Z_OK,zlib_error_message(err)) }/* * 解压缩数据到对象 */template<typename T>inline typename std::enable_if<std::is_class<T>::value>::type uncompress_obj (T &dest,const void *source, size_t sourceLen){ auto destLen=sizeof(T); zlib_mem_uncompress(std::addressof(dest),&destLen,source,sourceLen); }#endif /* INCLUDE_ZLIB_WRAPPER_H_ */
代码在VS2015和MingW5.2.0下编译通过
- 标签:
-
技术分享
您可能感兴趣的新闻 换一批
热门文章
现在下载,可享30天免费试用