zlib的简单使用
1.介绍
zlib 是一个广泛使用的数据压缩库,它提供了内存中的压缩和解压缩功能,并能够检查解压数据的完整性。zlib 支持读写 gzip (.gz) 格式的文件,并且默认使用 deflate 算法进行数据压缩,这是一种增强的 Huffman 编码算法。
2.安装
3.一次性读入内存解压缩compress和uncompress
#include <stdio.h>
#include "zlib.h"
int main()
{
/* 原始数据 */
unsigned char strSrc[] = "hello world!中文测试 yes";
unsigned char buf[1024] = {0};
unsigned char strDst[1024] = {0};
unsigned long srcLen = sizeof(strSrc);
unsigned long bufLen = sizeof(buf);
unsigned long dstLen = sizeof(strDst);
printf("Src string:%s\nLength:%ld\n", strSrc, srcLen);
/* 压缩 */
compress(buf, &bufLen, strSrc, srcLen);
printf("After Compressed Length:%ld\n", bufLen);
/* 解压缩 */
uncompress(strDst, &dstLen, buf, bufLen);
printf("After UnCompressed Length:%ld\n",dstLen);
printf("UnCompressed String:%s\n",strDst);
return 0;
}
示例解压缩一段字符串,对文件使用这两个函数时,也是一次性在内存中进行解压缩,适用于小文件,大文件应采用分块流式解压缩。
4.分块解压缩(流式)
官方示例 zlib 使用示例
#include <iostream>
#include <vector>
#include <fstream>
#include <zlib.h>
#include <spdlog/spdlog.h>
#include <stdio.h>
bool compress_data(const std::string& input_file_name, const std::string& output_file_name){
std::ifstream input_file(input_file_name, std::ios::binary);
if (!input_file) {
spdlog::error("Failed to open input file: {}", input_file_name);
return false;
}
std::ofstream output_file(output_file_name, std::ios::binary);
if (!output_file) {
spdlog::error("Failed to open output file: {}", output_file_name);
return false;
}
// 设置压缩参数zstream
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
// 初始化压缩流
if(deflateInit(&strm, Z_DEFAULT_COMPRESSION) != Z_OK){
spdlog::error("Failed to initialize deflate stream");
return false;
}
// 读取输入文件并压缩数据
const int buffer_size = 16 * 1024;
std::vector<char> buffer(buffer_size);
do {
input_file.read(buffer.data(), buffer_size);
strm.avail_in = static_cast<uInt>(input_file.gcount()); //读到的字节数
strm.next_in = reinterpret_cast<Bytef*>(buffer.data()); //输入缓冲区
do {
std::vector<char> output_buffer(buffer_size);
strm.avail_out = buffer_size;
strm.next_out = reinterpret_cast<Bytef*>(output_buffer.data());
// 压缩数据
int result = deflate(&strm, input_file.eof() ? Z_FINISH : Z_NO_FLUSH); //是否到文件末尾
if (result == Z_STREAM_ERROR){
spdlog::error("Error during compression: {}", strm.msg);
deflateEnd(&strm);
return false;
}
//加密
// 写入压缩后的数据到输出文件 发送到网络
std::streamsize compressed_size = buffer_size - strm.avail_out;
output_file.write(output_buffer.data(), compressed_size);
} while(strm.avail_out == 0);
} while(!input_file.eof());
// 压缩结束
deflateEnd(&strm);
input_file.close();
output_file.close();
return true;
}
bool decompress_data(const std::string& input_file_name, const std::string& output_file_name){
std::ifstream input_file(input_file_name, std::ios::binary);
if (!input_file) {
spdlog::error("Failed to open input file: {}", input_file_name);
return false;
}
std::ofstream output_file(output_file_name, std::ios::binary);
if(!output_file){
spdlog::error("faild to open output file: {}", output_file_name);
}
// 设置解压缩参数
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
//初始化解压缩流
if(inflateInit(&strm) != Z_OK){
spdlog::error("Failed to initialize inflate stream");
return false;
}
const int buffer_size = 16 * 1024;
std::vector<char> buffer(buffer_size);
do {
input_file.read(buffer.data(), buffer_size);
//格式转换
strm.avail_in = static_cast<uInt>(input_file.gcount());
strm.next_in = reinterpret_cast<Bytef*>(buffer.data());
do {
std::vector<char> output_file_buffer(buffer_size);
strm.avail_out = buffer_size;
strm.next_out = reinterpret_cast<Bytef*>(output_file_buffer.data());
//解压缩数据
int result = inflate(&strm, input_file.eof() ? Z_FINISH : Z_NO_FLUSH);
if (result == Z_STREAM_ERROR){
spdlog::error("Error during decompression: {}", strm.msg);
inflateEnd(&strm);
return false;
}
//写入解压缩后的数据到输出文件
std::streamsize uncompressed_size = buffer_size - strm.avail_out;
output_file.write(output_file_buffer.data(), uncompressed_size);
} while(strm.avail_out == 0);
} while(!input_file.eof());
//解压缩结束
inflateEnd(&strm);
input_file.close();
output_file.close();
return true;
}
int main(){
std::string input_file_name = "/root/test1/OIP-C.jpg";
std::string compressed_file_name = "/root/test1/compressed.bin";
std::string decompressed_file_name = "/root/test1/decompressed.jpg";
if(compress_data(input_file_name, compressed_file_name)){
spdlog::info("Data compressed successfully.");
}
else {
spdlog::error("Failed to compress data.");
return 1;
}
if(decompress_data(compressed_file_name, decompressed_file_name)){
spdlog::info("Data decompressed successfully.");
}
else {
spdlog::error("Failed to decompress data.");
return 1;
}
return 0;
}
5.压缩的流程
初始化结构体z_stream
初始化一个 z_stream 结构体 strm,并将一些字段设置为默认值:
zalloc 和 zfree 设置为 Z_NULL,表示使用默认的内存分配和释放函数。
opaque 设置为 Z_NULL,表示没有附加的数据。
avail_in 设置为 0,表示输入缓冲区中可用的数据长度为 0。
next_in 设置为 Z_NULL,表示输入缓冲区的指针为 NULL。
初始化压缩流(deflateInit 函数)
int deflateInit(z_stream strm, int level);*
strm:指向 z_stream 结构体的指针。
level:压缩级别,范围从 Z_NO_COMPRESSION 到 Z_BEST_COMPRESSION。
使用 deflateInit 函数初始化压缩流,并检查初始化是否成功。如果初始化失败,则记录错误信息并返回 false。
开始压缩 (deflate函数)
int deflate(z_stream strm, int flush);*
strm:指向 z_stream 结构体的指针。
flush:刷新标志,可以是 Z_NO_FLUSH、Z_PARTIAL_FLUSH、Z_SYNC_FLUSH、Z_FULL_FLUSH 或 Z_FINISH。
外部的 do-while 循环会一直执行,直到输入文件 input_file 读取完毕。
内部的 do-while 循环用于处理每次压缩操作。
初始化一个输出缓冲区 output_buffer,大小与输入缓冲区相同。
设置 avail_out 和 next_out 来指向输出缓冲区。
使用 deflate 函数进行压缩操作。如果当前是文件末尾,则传入 Z_FINISH,否则传入 Z_NO_FLUSH。
检查压缩结果是否为 Z_STREAM_ERROR,如果是则记录错误信息并结束压缩流。
计算实际压缩的字节数 compressed_size,并将其写入输出文件 output_file
结束释放资源(deflateEnd)
6.解压流程
解压也是类似的操作,不在赘述。稍加修改就能应用于网络传输,各种文件解压缩等。

浙公网安备 33010602011771号