zlib压缩库封装 及其使用
FlateCompressor是一个基于zlib库实现的DEFLATE算法压缩/解压缩工具。它采用PImpl模式隐藏实现细节,通过RAII机制自动管理资源,禁止拷贝以防止重复释放。核心功能包括支持0-9级压缩级别调节,提供二进制数据的无损压缩与解压。实现上使用deflateBound预分配输出缓冲区,inflate进行流式解压,并重用z_stream状态优化性能。该设计平衡了性能与易用性,适用于需
文章目录
FlateCompressor 代码大纲介绍
一、整体概述
-
核心功能
-
基于 zlib 库实现 DEFLATE 算法的压缩/解压缩
-
支持压缩级别调节(0-9 级)
-
提供二进制数据的无损压缩与解压
-
-
设计特点
-
PImpl 模式:隐藏 zlib 实现细节,降低耦合
-
资源安全:使用
unique_ptr
自动管理内存 -
禁止拷贝:防止重复释放资源(删除拷贝构造/赋值)
-
RAII 机制:构造函数初始化资源,析构函数自动清理
-
二、类结构解析
class FlateCompressor {
public:
// 构造/析构
FlateCompressor();
~FlateCompressor();
// 禁用拷贝
FlateCompressor(const FlateCompressor&) = delete;
FlateCompressor& operator=(const FlateCompressor&) = delete;
// 核心接口
std::vector<uint8_t> Compress(...); // 压缩
std::vector<uint8_t> Decompress(...); // 解压
};
三、关键实现细节
-
PImpl 结构体(Impl)
struct Impl { z_stream zs; // zlib 流控制结构 bool initialized; // 初始化标志位 // 构造/析构中管理 zlib 资源 };
-
封装 zlib 状态,避免头文件暴露 zlib 依赖
-
析构时自动调用
deflateEnd()
防止内存泄漏
-
-
压缩流程(Compress)
graph TD A[检查输入数据] --> B{已初始化?} B -->|否| C[deflateInit] B -->|是| D[deflateReset] E[预分配输出缓冲区] --> F[deflateBound估算大小] G[执行压缩] --> H{是否Z_STREAM_END?} H -->|成功| I[截断有效数据] H -->|失败| J[返回空向量]
-
解压流程(Decompress)
graph TD A[初始化z_stream] --> B[循环解压] B --> C[4KB临时缓冲区] D[逐块inflate] --> E{检查Z_OK/Z_STREAM_END} E -->|失败| F[立即终止] G[拼接输出数据] --> H[返回完整解压数据]
四、技术亮点
-
动态缓冲区管理
-
压缩:使用
deflateBound()
精准预分配最大输出空间 -
解压:采用流式处理(4KB 分块),避免内存浪费
-
-
状态复用优化
-
通过
deflateReset()
重用已初始化的 z_stream -
减少重复初始化开销(适合多次压缩场景)
-
-
健壮性设计
-
空输入检查:直接返回空向量
-
错误码处理:压缩失败返回空结果
-
内存清零:
memset(&zs, 0, ...)
防止野指针
-
五、使用示例
// 压缩示例
FlateCompressor compressor;
auto compressed = compressor.Compress(raw_data, 9);
// 解压示例
auto original_data = compressor.Decompress(compressed);
六、潜在改进方向
-
异常处理
- 当前返回空向量可改为抛出异常携带错误码
-
流式支持
- 添加
CompressChunk()
支持分块压缩
- 添加
-
自定义分配器
- 允许传入自定义内存分配回调函数
-
多线程安全
- 增加锁机制支持并发调用
七、依赖说明
-
核心库:zlib (通过
fx_zlib.h
封装) -
关键头文件:
#include "fxcodec/fx_codec_zlib_wrap.h" #include "../fx_zlib/include/fx_zlib.h"
该实现平衡了性能与易用性,适用于 PDF 处理等需要 Flate 编解码的场景。
头文件
#pragma once
#include <vector>
#include <cstdint>
#include <memory>
class FlateCompressor {
public:
FlateCompressor();
~FlateCompressor();
// 禁用拷贝(防止资源重复释放)
FlateCompressor(const FlateCompressor&) = delete;
FlateCompressor& operator=(const FlateCompressor&) = delete;
// 压缩数据(返回压缩后的二进制数据)
std::vector<uint8_t> Compress(const std::vector<uint8_t>& input_data, int compression_level = 6);//压缩范围 0 到9
// 解压数据(返回原始二进制数据)
std::vector<uint8_t> Decompress(const std::vector<uint8_t>& compressed_data);
private:
// PImpl 模式:隐藏 zlib 实现细节
struct Impl;
std::unique_ptr<Impl> impl_;
};
实现文件
#include "fxcodec/fx_codec_zlib_wrap.h"
#include "../fx_zlib/include/fx_zlib.h"
#include <cstring> // for memset
// PImpl 结构体,封装 zlib 状态
struct FlateCompressor::Impl {
z_stream zs;
bool initialized = false;
Impl() {
memset(&zs, 0, sizeof(zs));
}
~Impl() {
if (initialized) {
deflateEnd(&zs); // 确保资源释放
}
}
};
// 构造函数
FlateCompressor::FlateCompressor() : impl_(std::make_unique<Impl>()) {}
// 析构函数(unique_ptr 自动释放 impl_)
FlateCompressor::~FlateCompressor() = default;
// 压缩数据
std::vector<uint8_t> FlateCompressor::Compress(const std::vector<uint8_t>& input_data, int compression_level) {
if (input_data.empty()) {
return {};
}
// 初始化 zlib(如果未初始化)
if (!impl_->initialized) {
if (deflateInit(&impl_->zs, compression_level) != Z_OK) {
return {};
}
impl_->initialized = true;
}
else {
deflateReset(&impl_->zs); // 重用已有的 z_stream
}
// 设置输入数据
impl_->zs.next_in = const_cast<Bytef*>(input_data.data());
impl_->zs.avail_in = static_cast<uInt>(input_data.size());
// 预分配输出缓冲区
std::vector<uint8_t> output_buffer(deflateBound(&impl_->zs, static_cast<uLong>(input_data.size())));
// 设置输出缓冲区
impl_->zs.next_out = output_buffer.data();
impl_->zs.avail_out = static_cast<uInt>(output_buffer.size());
// 执行压缩
int ret = deflate(&impl_->zs, Z_FINISH);
if (ret != Z_STREAM_END) {
return {}; // 压缩失败
}
// 调整缓冲区大小以匹配实际压缩数据
output_buffer.resize(impl_->zs.total_out);
return output_buffer;
}
// 解压数据
std::vector<uint8_t> FlateCompressor::Decompress(const std::vector<uint8_t>& compressed_data) {
if (compressed_data.empty()) {
return {};
}
z_stream zs;
memset(&zs, 0, sizeof(zs));
if (inflateInit(&zs) != Z_OK) {
return {};
}
zs.next_in = const_cast<Bytef*>(compressed_data.data());
zs.avail_in = static_cast<uInt>(compressed_data.size());
// 逐步解压(因为解压后的大小未知)
std::vector<uint8_t> output_buffer;
uint8_t temp_buffer[4096]; // 临时缓冲区
do {
zs.next_out = temp_buffer;
zs.avail_out = sizeof(temp_buffer);
int ret = inflate(&zs, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
inflateEnd(&zs);
return {};
}
// 将解压的数据追加到输出缓冲区
size_t bytes_decoded = sizeof(temp_buffer) - zs.avail_out;
output_buffer.insert(output_buffer.end(), temp_buffer, temp_buffer + bytes_decoded);
} while (zs.avail_out == 0);
inflateEnd(&zs);
return output_buffer;
}
使用代码
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include "FlateCompressor.h" // 包含头文件
// 打印二进制数据的十六进制表示(调试用)
void PrintHex(const std::vector<uint8_t>& data, size_t max_len = 16) {
std::cout << "Hex Data (" << data.size() << " bytes): ";
for (size_t i = 0; i < std::min(data.size(), max_len); ++i) {
printf("%02X ", data[i]);
}
if (data.size() > max_len) std::cout << "...";
std::cout << std::endl;
}
// 生成测试数据(可自定义内容)
std::vector<uint8_t> GenerateTestData(size_t size) {
std::vector<uint8_t> data(size);
for (size_t i = 0; i < size; ++i) {
data[i] = static_cast<uint8_t>(i % 256); // 循环填充0-255
}
return data;
}
// 压缩测试函数
void TestCompression(const std::vector<uint8_t>& original_data, int level) {
FlateCompressor compressor;
auto start = std::chrono::high_resolution_clock::now();
std::vector<uint8_t> compressed = compressor.Compress(original_data, level);
auto end = std::chrono::high_resolution_clock::now();
if (compressed.empty()) {
std::cerr << "Compression failed!" << std::endl;
return;
}
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
double ratio = original_data.empty() ? 0 :
(1.0 - (double)compressed.size() / original_data.size()) * 100;
std::cout << "\n=== Compression Test (Level " << level << ") ===" << std::endl;
std::cout << "Original Size: " << original_data.size() << " bytes" << std::endl;
std::cout << "Compressed Size: " << compressed.size() << " bytes" << std::endl;
std::cout << "Compression Ratio: " << ratio << "%" << std::endl;
std::cout << "Time: " << duration.count() << " μs" << std::endl;
PrintHex(compressed);
}
// 解压测试函数
void TestDecompression(const std::vector<uint8_t>& compressed_data) {
FlateCompressor compressor;
auto start = std::chrono::high_resolution_clock::now();
std::vector<uint8_t> decompressed = compressor.Decompress(compressed_data);
auto end = std::chrono::high_resolution_clock::now();
if (decompressed.empty()) {
std::cerr << "Decompression failed!" << std::endl;
return;
}
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "\n=== Decompression Test ===" << std::endl;
std::cout << "Compressed Size: " << compressed_data.size() << " bytes" << std::endl;
std::cout << "Decompressed Size: " << decompressed.size() << " bytes" << std::endl;
std::cout << "Time: " << duration.count() << " μs" << std::endl;
PrintHex(decompressed);
}
// 完整流程测试(压缩+解压)
void TestRoundTrip() {
// 生成测试数据(1MB随机数据)
const size_t test_size = 1024 * 1024;
std::vector<uint8_t> original_data = GenerateTestData(test_size);
std::cout << "=== Round Trip Test ===" << std::endl;
PrintHex(original_data);
// 测试不同压缩级别
for (int level = 0; level <= 9; ++level) {
FlateCompressor compressor;
// 压缩
std::vector<uint8_t> compressed = compressor.Compress(original_data, level);
if (compressed.empty()) {
std::cerr << "Level " << level << " compression failed!" << std::endl;
continue;
}
// 解压
std::vector<uint8_t> decompressed = compressor.Decompress(compressed);
if (decompressed.empty()) {
std::cerr << "Level " << level << " decompression failed!" << std::endl;
continue;
}
// 验证数据一致性
if (original_data != decompressed) {
std::cerr << "Level " << level << " data mismatch!" << std::endl;
} else {
double ratio = (1.0 - (double)compressed.size() / original_data.size()) * 100;
std::cout << "Level " << level << " OK. Ratio: " << ratio << "%" << std::endl;
}
}
}
int main() {
// 示例1:基础压缩/解压
std::string sample_text = "Hello, FlateCompressor! This is a test string for compression.";
std::vector<uint8_t> text_data(sample_text.begin(), sample_text.end());
std::cout << "=== Basic Text Test ===" << std::endl;
PrintHex(text_data);
TestCompression(text_data, 6); // 默认压缩级别
std::vector<uint8_t> compressed_text = FlateCompressor().Compress(text_data, 6);
TestDecompression(compressed_text);
// 示例2:大文件测试
std::vector<uint8_t> large_data = GenerateTestData(5 * 1024 * 1024); // 5MB数据
TestCompression(large_data, 9); // 最高压缩级别
// 示例3:往返测试
TestRoundTrip();
return 0;
}
更多推荐
所有评论(0)