用zlib解压.gz文件是最轻量可行路径,需安装对应平台zlib库、链接-lz、包含<zlib.h>,调inflateInit2(&strm, 16+MAX_WBITS)初始化流,手动管理next_in/avail_in和next_out/avail_out,循环调inflate并检查返回值,解压后文件名应安全剥离末尾“.gz”后缀。

用 zlib 解压 .gz 文件是最轻量可行的路径
直接手写解压缩算法不现实,C++ 标准库也不提供解压能力。实际项目中,zlib 是事实标准——它小、稳定、跨平台,且 .gz 是最常见需快速处理的压缩格式。别碰 bzip2 或 xz,除非明确要求;它们依赖更多、编译更麻烦,对“简单”目标是过度设计。
你需要:
– 安装 zlib(Linux 用 apt install zlib1g-dev,macOS 用 brew install zlib,Windows 推荐 vcpkg:vcpkg install zlib:x64-windows)
– 链接时加 -lz(Linux/macOS)或正确配置库目录(Windows)
– 头文件只包含 <zlib.h>,无需其他封装层
inflate() 不是开箱即用函数,必须手动管理流状态
很多人卡在调用 inflate() 返回 Z_DATA_ERROR 或 Z_STREAM_ERROR,根本原因是没初始化 z_stream 结构体,或没设置 avail_in/avail_out。它不像 fread() 那样自动推进指针。
关键步骤:
- 用
memset(&strm, 0, sizeof(strm))清零z_stream,再调inflateInit2(&strm, 16 + MAX_WBITS)(16+表示支持 gzip header) -
strm.next_in指向读入的压缩数据缓冲区,strm.avail_in必须设为当前有效字节数(不是缓冲区长度) -
strm.next_out指向输出缓冲区起始,strm.avail_out设为剩余空间字节数 - 每次调
inflate()后检查返回值:Z_OK继续,Z_STREAM_END表示完成,其他值需按错误码查zlib.h
一次性读入整个 .gz 文件再解压,比流式处理更稳妥
新手试图边读文件边解压,容易因缓冲区大小不匹配、EOF 判断不准导致截断或崩溃。对“简单程序”,直接把 .gz 文件全读进内存,再喂给 inflate(),逻辑清晰、容错强。
立即学习“C++免费学习笔记(深入)”;
示例片段(省略错误检查):
std::ifstream gz_file("test.gz", std::ios::binary | std::ios::ate);
size_t size = gz_file.tellg();
gz_file.seekg(0, std::ios::beg);
std::vector<unsigned char> gz_data(size);
gz_file.read(reinterpret_cast<char*>(gz_data.data()), size);
<p>z_stream strm;
memset(&strm, 0, sizeof(strm));
inflateInit2(&strm, 16 + MAX_WBITS);</p><p>strm.next_in = gz_data.data();
strm.avail_in = gz_data.size();
// 分配足够大的 output buffer,比如 4x 输入大小
std::vector<unsigned char> out(4 * size);
strm.next_out = out.data();
strm.avail_out = out.size();</p><p>int ret = inflate(&strm, Z_FINISH);
inflateEnd(&strm);
// ret == Z_STREAM_END 时,strm.total_out 是真实解压字节数</p>输出文件名不能硬编码,要从 .gz 后缀剥离
解压后文件名应自动去掉 .gz,否则用户得手动改名。但别用 string::replace() 粗暴替换所有 ".gz" —— 如果原文件叫 data.gz.txt.gz 就错了。
安全做法:
- 用
filename.rfind(".gz")找最后出现位置 - 确认该位置等于
filename.length() - 3,即后缀确实在末尾 - 然后用
filename.substr(0, pos)截取 - 注意 Windows 路径分隔符不影响此逻辑,
std::filesystem::path的stem()方法更健壮,但 C++17 起才有,若环境受限就手写
真正麻烦的是二进制数据写入:务必用 std::ofstream(..., std::ios::binary),漏掉 binary 标志在 Windows 下会把 \n 错误转成 \r\n,破坏原始内容。


















