简介:MINIZIP 压缩解压缩开发包面向希望在 C/C++ 工程中快速集成 ZIP 读写能力的开发者,尤其适合嵌入式、桌面小工具等对体积和依赖敏感的场景,可免去从零编译 zlib 与 minizip 的麻烦。包内共 7 个文件,由 5 个 h 头文件与 2 个静态库组成:头文件覆盖 zip/unzip 接口声明,以及流式读写、文件系统适配等模块定义,两个 lib 是 zlib 与 minizip 的编译产物,压缩包约 137KB,解压后直接加入工程参与链接即可调用。目前已有 877 人学习下载。该版本在原生接口基础上支持显示整个压缩包的解压进度和单个文件的解压进度,并保留 AES-256 加密、UTF-8 等多字节编码文件名处理能力;读者可据此完成压缩、解压、进度回调与异常退出的完整流程,适合需要现成库文件与可复用接口的中级开发者参考。
1. MINIZIP 压缩解压缩这套库,先别急着把 .lib 拖进工程
MINIZIP 压缩解压缩这套东西,最常见的翻车现场不是 API 不会调,而是把 zlibstatic.lib 和 minizip.lib 拖进工程后,Release 能编、Debug 一跑就崩。一个桌面工具要读写 zip,不想额外带 DLL,静态库看起来最省事;但架构、CRT、链接顺序任意一个没对齐,报错就从 LNK2019 一路排到运行时堆损坏。有人把 MINIZIP 搜成 minizi,拿到库却不知道从哪开始。这篇按我装环境的路子走:先核对库,再接工程,最后用压缩解压闭环验证,适合 Windows C++ 开发者照着复现。
2. 环境核对:MINIZIP 静态库的版本、架构和运行库先对齐
2.1 这套文件到底包含什么:头文件、zlibstatic.lib、minizip.lib
拿到压缩包后,我一般不会直接解压到桌面,而是先在工程目录里固定一个第三方库位置,比如third_party/minizip。目录结构要让人一眼看出头文件和库文件分开,后面 Visual Studio 和 CMake 都好配。常见做法是下面这种布局:
third_party/minizip/ include/ zlib.h zconf.h zip.h unzip.h ioapi.h iowin32.h lib/ x64/ Release/ zlibstatic.lib minizip.lib x86/ Release/ zlibstatic.lib minizip.lib这套资源的关键实物是两个静态库:zlibstatic.lib是 zlib 的静态链接版本,负责 deflate/inflate、CRC32 这些底层压缩算法;minizip.lib是 minizip 的静态库,负责 zip 容器的读写,比如打开 zip、遍历条目、写文件头、关闭条目。头文件里,zlib.h和zconf.h来自 zlib,zip.h、unzip.h、ioapi.h来自 minizip。少一个头文件,编译期就会报找不到声明;头文件和 lib 版本不一致,麻烦会推迟到链接期或运行期。
| 文件 | 作用 | 常见问题 |
|---|---|---|
zlibstatic.lib | 静态链接的 zlib,提供压缩算法和 CRC | 和工程运行库/MT、/MD不一致 |
minizip.lib | zip 容器读写,调用 zlib | 链接顺序放在 zlib 后面导致符号找不到 |
zlib.h/zconf.h | zlib 类型、版本宏、函数声明 | 和 lib 版本不一致,结构体或宏对不上 |
zip.h/unzip.h | minizip 压缩、解压 API | 只加了库路径,忘了加 minizip 头文件目录 |
ioapi.h/iowin32.h | 文件 IO 适配层 | 自己编源码时漏掉ioapi.c或iowin32.c |
如果资源里只有两个.lib,头文件必须从同版本源码补齐,不要拿旧版zlib.h去配新版zlibstatic.lib。zlib 的ZLIB_VERSION宏在头文件里,运行期还能用zlibVersion()打印实际库版本,两个值一致,至少说明头文件和库没有串版本。minizip 这边不一定有统一的版本宏,我一般看zip.h、unzip.h里的函数声明是否和 lib 对得上,尤其是zipOpenNewFileInZip4_64、unzOpen64这类 64 位接口有没有声明。
2.2 用 dumpbin 查 x86/x64 和 /MT /MD
静态库最怕“看起来都是 lib,实际架构不一样”。x64 工程链了 x86 的zlibstatic.lib,链接器会直接给LNK1112;工程是/MD,库是/MT,常见LNK2038运行库不匹配。先别写业务代码,打开对应架构的开发者命令提示符,用dumpbin把两个库都扫一遍。命令不复杂,但要在能找到dumpbin的环境里执行:
:: 查机器架构:8664 是 x64,14C 是 x86 dumpbin /headers zlibstatic.lib | findstr /i "machine" dumpbin /headers minizip.lib | findstr /i "machine" :: 查运行库:MSVCRT 对应 /MD,LIBCMT 对应 /MT dumpbin /directives zlibstatic.lib | findstr /i "RuntimeLibrary" dumpbin /directives minizip.lib | findstr /i "RuntimeLibrary"/headers看的是 COFF 头里的 machine 字段,输出里出现8664 machine (x64)就说明这个 lib 是 64 位;出现14C machine (x86)就是 32 位。/directives看的是库文件里嵌入的默认库指令,常见对应关系如下:
| dumpbin 输出 | 对应运行库 | 工程里怎么设 |
|---|---|---|
/DEFAULTLIB:MSVCRT | /MDRelease | C/C++ → 代码生成 → 运行库选/MD |
/DEFAULTLIB:MSVCRTD | /MDdDebug | Debug 工程选/MDd,或改用 Release 库 |
/DEFAULTLIB:LIBCMT | /MTRelease | 运行库选/MT,不要和/MD混 |
/DEFAULTLIB:LIBCMTD | /MTdDebug | Debug 静态运行库,和 Release 库隔离 |
我踩过的坑是只看文件名,没看运行库。zlibstatic.lib名字里没有d,但工程是 Debug,链接器不一定立刻报错,跑起来在free或inflateEnd附近堆损坏,查起来像玄学。后来我养成习惯:新库进工程前先跑一遍dumpbin /directives,把/MT、/MD记在库目录的README里,谁再混用就直接对照。还有一点,静态链接 zlib 时不要定义ZLIB_DLL,否则zlib.h会把函数声明成dllimport,链接时出现__imp_inflate这类未解析符号,看起来像库没链上,实际是宏用错了。
2.3 版本选择:Release 优先,Debug 不要硬混
这套资源给的是编译好的静态库,最省事的用法是让工程也走 Release x64,运行库和库保持一致。很多桌面工具最终发布就是 Release,调试期如果一定要 Debug,我一般做两套目录:lib/x64/Release放这套库,lib/x64/Debug自己用同版本源码重编一份/MDd的 zlib 和 minizip。不要图省事把 Release 的zlibstatic.lib直接塞进 Debug 工程,C 库的堆分配和释放跨了 CRT,可能编得过、跑几次才崩,定位成本比重新编库高得多。
版本选择上,不要默认“越新越好”。如果项目已经有一份稳定的zlib.h,就优先找同版本的zlibstatic.lib;如果资源里的minizip.lib暴露了 zip64 接口,而业务只需要普通小文件,也可以先用基础 API 跑通,再决定要不要上 64 位接口。zlib 的 ABI 相对克制,但头文件里的ZLIB_VERSION和库实际版本最好一致;minizip 的函数签名在不同版本间有过调整,尤其是zipOpenNewFileInZip4_64这类带flag、zip64参数的接口,头文件和 lib 必须成套。
提示:拿到
.lib先做架构和运行库核对,再谈 API。架构不对是链接器报错,运行库不对可能拖到运行期才炸。
3. 接进工程:include、lib 目录和链接顺序一次配好
3.1 目录布局与头文件包含写法
工程里不要用“把 lib 复制到项目根目录”这种做法,短期省事,后面换 Debug/Release、换 x86/x64 一定乱。我一般固定成third_party/minizip/include和third_party/minizip/lib/<arch>/<config>,然后在工程属性里写相对路径或宏路径。头文件包含也统一:zlib 的用尖括号,minizip 的用引号,看到代码就知道来源。
#include <zlib.h> // zlib 版本宏、压缩常量 #include "zip.h" // 压缩:zipOpen、zipWriteInFileInZip #include "unzip.h" // 解压:unzOpen、unzReadCurrentFile如果zip.h内部已经包含zlib.h,也不要因此就删掉自己的zlib.h包含;显式写出来,后面排查版本宏更直接。头文件目录一般要加两个:include和include/minizip,因为有些 minizip 源码包把头文件放在子目录里,只加一个路径会在#include "zip.h"时找不到。
3.2 Visual Studio 属性页的四个位置
Visual Studio 工程里,我把配置集中在四个地方,不靠#pragma comment(lib, ...)散落在源文件中。#pragma不是不能用,但库路径一多,排查时容易漏看。属性页按下面配,注意每个配置平台分别检查,不要只改 Debug|x64 就以为 Release|x64 也生效。
| 位置 | 填什么 | 说明 |
|---|---|---|
| C/C++ → 常规 → 附加包含目录 | ..\third_party\minizip\include;..\third_party\minizip\include\minizip | 分号分隔,路径按工程实际改 |
| 链接器 → 常规 → 附加库目录 | ..\third_party\minizip\lib\x64\Release | Debug 工程不要指到 Release 目录 |
| 链接器 → 输入 → 附加依赖项 | minizip.lib;zlibstatic.lib; | minizip 放前面,zlib 放后面 |
| C/C++ → 预处理器 → 预处理器定义 | _CRT_SECURE_NO_WARNINGS | 减少fopen这类安全警告,不改变运行库 |
链接顺序这里要多说一句:minizip.lib调用 zlib 的inflate、deflate、crc32,所以写minizip.lib;zlibstatic.lib;更符合依赖方向。MSVC 对静态库的解析顺序有要求,反过来写有时也能过,但换一个链接器或开/OPT:REF就可能暴露未解析符号。运行库设置和dumpbin结果保持一致:库是/MD,工程 Release 就选/MD;库是/MT,工程就选/MT。不要在同一个工程里一部分库/MT、一部分/MD,C 运行库的堆不是同一个,释放时容易出问题。
3.3 CMake 工程的链接写法
如果工程用 CMake,我一般不写死link_directories,而是用find_library加NO_DEFAULT_PATH,避免 CMake 悄悄从系统路径抓到另一个同名库。下面这段可以直接改成自己的路径:
cmake_minimum_required(VERSION 3.16) project(minizip_demo LANGUAGES CXX) set(MZ_ROOT "${CMAKE_SOURCE_DIR}/third_party/minizip") set(MZ_LIB_DIR "${MZ_ROOT}/lib/x64/Release") add_executable(minizip_demo main.cpp) target_include_directories(minizip_demo PRIVATE "${MZ_ROOT}/include" "${MZ_ROOT}/include/minizip" ) # NO_DEFAULT_PATH 很重要,防止误链系统里的 zlib find_library(MINIZIP_LIB NAMES minizip PATHS "${MZ_LIB_DIR}" NO_DEFAULT_PATH) find_library(ZLIB_LIB NAMES zlibstatic PATHS "${MZ_LIB_DIR}" NO_DEFAULT_PATH) if(NOT MINIZIP_LIB OR NOT ZLIB_LIB) message(FATAL_ERROR "minizip.lib 或 zlibstatic.lib 没找到,先检查 MZ_LIB_DIR") endif() target_link_libraries(minizip_demo PRIVATE "${MINIZIP_LIB}" "${ZLIB_LIB}" ) target_compile_definitions(minizip_demo PRIVATE _CRT_SECURE_NO_WARNINGS )find_library里NAMES写的是不带.lib的名字,CMake 会自动补后缀。NO_DEFAULT_PATH让查找只发生在指定目录,适合这种自带第三方库的项目。target_link_libraries里MINIZIP_LIB放在ZLIB_LIB前面,和 Visual Studio 附加依赖项的顺序一致。target_compile_definitions只加_CRT_SECURE_NO_WARNINGS,不要加ZLIB_DLL,静态链接不需要它。
3.4 先编一个只调 zlibVersion 的空壳
接完路径不要立刻写压缩业务,先编一个只调 zlib 的空壳。这个步骤能把“头文件路径不对”“库架构不对”“运行库不匹配”三类问题分开。代码只有几行:
#include <zlib.h> #include <iostream> int main() { std::cout << "header ZLIB_VERSION=" << ZLIB_VERSION << "\n"; std::cout << "runtime zlibVersion=" << zlibVersion() << "\n"; return 0; }能编过、能运行,说明zlibstatic.lib的架构和运行库至少对上了。接下来再把zip.h、unzip.h加进来,调用一个zipOpen创建空 zip,确认 `minizip.lib
本文还有配套的精品资源,点击获取