c++封装一个zlib类(附带测试源码)
本文主要讲zlib使用qt编译,还有就是把zlib的常用函数封装成一个类
·
zlib
zlib是最常用的压缩与解压缩的库,对于服务器来说想要提高数据的收发功能就需要对数据进行压缩,压缩的另一个好处是让数据加密,也能减少网络传输的时间,所以本章就讲解zlib的基础功能压缩与解压缩。
zlib的安装
zlib下载链接: zlib
zlib的编译,我是用的是qt编译(qt编译的好处是能多个平台都按照相同流程编译)
1.
2.去到zlib的源码位置选cmakelist.txt然后点open
3.
4.
5.
6.查看编译好后的路径

: m_level(level), m_strategy(strategy) {
if (m_level < Z_NO_COMPRESSION || m_level > Z_BEST_COMPRESSION) {
throw ZlibError("无效的压缩级别");
}
}
~ZlibWrapper()
{
if(m_ZlibWrapper!=nullptr)
{
delete m_ZlibWrapper;
}
}
//================ 文件压缩/解压 ================
void compressFile(const std::string& inputPath, const std::string& outputPath) {
std::ifstream in(inputPath, std::ios::binary);
std::ofstream out(outputPath, std::ios::binary);
if (!in || !out) throw ZlibError("文件打开失败");
initCompression();
constexpr size_t CHUNK = 16384;
std::vector<Bytef> in_buf(CHUNK), out_buf(CHUNK);
int flush;
do {
in.read(reinterpret_cast<char*>(in_buf.data()), CHUNK);
m_stream.avail_in = static_cast<uInt>(in.gcount());
m_stream.next_in = in_buf.data();
flush = in.eof() ? Z_FINISH : Z_NO_FLUSH;
do {
m_stream.avail_out = CHUNK;
m_stream.next_out = out_buf.data();
checkZlibResult(deflate(&m_stream, flush), "压缩失败");
out.write(reinterpret_cast<char*>(out_buf.data()),
CHUNK - m_stream.avail_out);
} while (m_stream.avail_out == 0);
} while (flush != Z_FINISH);
deflateEnd(&m_stream);
}
void decompressFile(const std::string& inputPath, const std::string& outputPath) {
std::ifstream in(inputPath, std::ios::binary);
std::ofstream out(outputPath, std::ios::binary);
if (!in || !out) throw ZlibError("文件打开失败");
initDecompression();
constexpr size_t CHUNK = 16384;
std::vector<Bytef> in_buf(CHUNK), out_buf(CHUNK);
do {
in.read(reinterpret_cast<char*>(in_buf.data()), CHUNK);
m_stream.avail_in = static_cast<uInt>(in.gcount());
if (m_stream.avail_in == 0) break;
m_stream.next_in = in_buf.data();
do {
m_stream.avail_out = CHUNK;
m_stream.next_out = out_buf.data();
checkZlibResult(inflate(&m_stream, Z_NO_FLUSH), "解压失败");
out.write(reinterpret_cast<char*>(out_buf.data()),
CHUNK - m_stream.avail_out);
} while (m_stream.avail_out == 0);
} while (true);
inflateEnd(&m_stream);
}
//================ 字符串操作 ================
std::string compressString(const std::string& input) {
uLongf bound = compressBound(input.size());
std::string output(bound, '\0');
uLongf outlen = bound;
checkZlibResult(compress2(
reinterpret_cast<Bytef*>(&output[0]), // 允许修改内容
&outlen,
reinterpret_cast<const Bytef*>(input.data()),
input.size(),
m_level
), "字符串压缩失败");
output.resize(outlen);
return output;
}
std::string decompressString(const std::string& compressed) {
uLongf destLen = compressed.size() * 10; // 初始预估解压大小
std::string output(destLen, '\0');
int ret;
do {
ret = uncompress(
reinterpret_cast<Bytef*>(&output[0]),
&destLen,
reinterpret_cast<const Bytef*>(compressed.data()),
compressed.size()
);
if (ret == Z_BUF_ERROR) { // 缓冲区不足时扩容
destLen *= 2;
output.resize(destLen);
} else {
checkZlibResult(ret, "字符串解压失败");
}
} while (ret == Z_BUF_ERROR);
output.resize(destLen);
return output;
}
//================ 分块压缩 ================
void startChunkedCompression(std::ofstream& outStream) {
initCompression();
m_chunkedMode = true;
m_buffer.reserve(16384); // 预分配缓冲区
m_outStream = &outStream; // 保存输出流引用
}
void compressChunk(const char* data, size_t length) {
if (!m_chunkedMode) throw ZlibError("未启动分块模式");
m_stream.avail_in = length;
m_stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
do {
m_stream.avail_out = m_buffer.capacity();
m_stream.next_out = reinterpret_cast<Bytef*>(m_buffer.data());
checkZlibResult(deflate(&m_stream, Z_SYNC_FLUSH), "分块压缩失败");
m_outStream->write(m_buffer.data(),
m_buffer.capacity() - m_stream.avail_out);
} while (m_stream.avail_in > 0);
}
void endChunkedCompression() {
if (!m_chunkedMode) return;
// 完成压缩
m_stream.avail_in = 0;
int ret;
do {
m_stream.avail_out = m_buffer.capacity();
m_stream.next_out = reinterpret_cast<Bytef*>(m_buffer.data());
ret = deflate(&m_stream, Z_FINISH);
m_outStream->write(m_buffer.data(),
m_buffer.capacity() - m_stream.avail_out);
} while (ret == Z_OK);
checkZlibResult(ret, "分块结束失败");
deflateEnd(&m_stream);
m_chunkedMode = false;
}
void startChunkedDecompression() {
initDecompression();
m_decompressPending = false;
m_inflateFinished = false;
}
std::string decompressChunk(const char* data, size_t length) {
if (m_inflateFinished) return "";
m_stream.avail_in = length;
m_stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(data));
std::string output;
constexpr size_t OUT_CHUNK = 32768; // 32KB输出块
std::vector<Bytef> out_buf(OUT_CHUNK);
do {
m_stream.avail_out = OUT_CHUNK;
m_stream.next_out = out_buf.data();
int ret = inflate(&m_stream, Z_SYNC_FLUSH);
if (ret == Z_STREAM_END) {
m_inflateFinished = true;
} else {
checkZlibResult(ret, "分块解压失败");
}
// 将解压后的数据添加到输出
size_t have = OUT_CHUNK - m_stream.avail_out;
if (have > 0) {
output.append(reinterpret_cast<char*>(out_buf.data()), have);
}
// 处理未消费完的输入数据(跨块边界情况)
if (m_stream.avail_in > 0 && ret != Z_STREAM_END) {
m_decompressPending = true;
m_pendingData.assign(
reinterpret_cast<char*>(m_stream.next_in),
m_stream.avail_in
);
break;
}
} while (m_stream.avail_out == 0);
return output;
}
void endChunkedDecompression() {
if (m_decompressPending) {
// 处理剩余数据(可能需要多次调用)
std::string finalOutput = decompressChunk(m_pendingData.data(), m_pendingData.size());
if (!finalOutput.empty()) {
// 可根据需求处理最终输出
}
}
inflateEnd(&m_stream);
}
//================ 扩展功能 ================
//设置压缩级别
void setCompressionLevel(int level) {
if (level < 0 || level > 9) throw ZlibError("无效压缩级别");
m_level = level;
}
//设置策略
void setStrategy(int strategy)
{
if (strategy < Z_DEFAULT_STRATEGY || strategy > Z_FIXED) {
throw ZlibError("无效策略");
}
m_strategy = strategy;
}
static uint32_t calculateAdler32(const std::string& data) {
return adler32(0L,
reinterpret_cast<const Bytef*>(data.data()),
data.size());
}
void reserveBuffer(size_t size) {
m_buffer.clear();
m_buffer.reserve(size);
}
class ZlibError : public std::runtime_error {
using runtime_error::runtime_error;
};
static ZlibWrapper*m_ZlibWrapper;
private:
int m_level;
int m_strategy;
z_stream m_stream{};
std::vector<char> m_buffer;
bool m_chunkedMode = false;
std::ofstream* m_outStream = nullptr;
bool m_decompressPending = false; // 是否有未处理的输入数据
bool m_inflateFinished = false; // 解压是否完成
std::string m_pendingData; // 跨块未处理的输入数据
void initCompression() {//初始化压缩
m_stream.zalloc = Z_NULL;
m_stream.zfree = Z_NULL;
m_stream.opaque = Z_NULL;
checkZlibResult(deflateInit2(&m_stream, m_level, Z_DEFLATED,
MAX_WBITS, 8, m_strategy), "压缩初始化失败");
}
void initDecompression() {//初始化解压缩
m_stream.zalloc = Z_NULL;
m_stream.zfree = Z_NULL;
m_stream.opaque = Z_NULL;
checkZlibResult(inflateInit2(&m_stream, MAX_WBITS), "解压初始化失败");
}
void checkZlibResult(int code, const char* context) {//异常打印
if (code >= Z_OK) return;
std::string msg = context;
if (m_stream.msg) {
msg += ": ";
msg += m_stream.msg;
}
throw ZlibError(msg);
}
};
ZlibWrapper *ZlibWrapper::m_ZlibWrapper=new ZlibWrapper;
测试代码
char buf[100]="hehahhhao00000000lovework阿斯\n\afafaw\zczczczczc)(c奥的\n\n";
std::string com=ZlibWrapper::m_ZlibWrapper->compressString(buf);
std::string decom= ZlibWrapper::m_ZlibWrapper->decompressString(com);
ZlibWrapper::m_ZlibWrapper->compressFile("./opencv_world310.dll","./0opencv_world310.dll");
ZlibWrapper::m_ZlibWrapper->decompressFile("./0opencv_world310.dll","./1opencv_world310.dll");
printf("%s:%d %s:%d\n",buf,decom.size(),decom.c_str(),com.size());
测试效果
解压后文件对比
更多推荐
所有评论(0)