前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >zlib库内存压缩解压缩函数的C++便利性封装

zlib库内存压缩解压缩函数的C++便利性封装

作者头像
10km
发布2019-05-25 22:36:03
4.4K0
发布2019-05-25 22:36:03
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433748

zlib是提供数据压缩用的函数库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表,普遍为许多软件所使用。

在使用zlib进行内存压缩解压缩的的时候主要用到的函数就是两个compress/uncompress。为了在C++中使用更方便,做一些便利性封装是非常必要的。

下面的代码中主要对zlib的内存压缩和解压缩进行了C++封装,出错以异常抛出。

因为zlib没办法估计解压缩后数据的长度,所以解压缩的时候,如果不知道源数据压缩之前的长度,就得估算一个长度来设置输出缓冲区大小,如果缓冲长度不足导致解压缩失败,就增大缓冲区再尝试直到解压缩成功。

代码语言:javascript
复制
/*
 * 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下编译通过

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年03月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档