[Windows/C] libzip 的编译和使用
<p>本文参考:</p><ul>
<li>Windwos zlib 下载和编译</li>
<li>Windwos 编译 libzip</li>
</ul>
<h2 id="0-准备工作">0. 准备工作</h2>
<p>编译器:我使用的编译器是 gcc(MinGW),此时需将编译器目录下的 <code>mingw32-make.exe</code> 改名为 <code>make.exe</code>,方便使用。</p>
<p>你需要 <strong>CMake</strong>,可以在 https://cmake.org/download/ 下载。下载解压后在 <code>bin</code> 目录下找到 <code>cmake-gui.exe</code>,我们使用的是这个 GUI 程序。<code>cmake.exe</code> 是它的命令行版本,不建议直接使用。</p>
<h2 id="1-编译-zlib">1. 编译 zlib</h2>
<p><strong>libzip 依赖 zlib,所以你需要先编译 zlib。</strong></p>
<p>先在 https://www.zlib.net/ 下载 zlib 源码,下载链接大概在</p>
<blockquote>
<p>The current release is publicly available here:</p>
</blockquote>
<p>这一行下面。可以看到在其根目录下有 <code>CMakeLists.txt</code> 文件。</p>
<p>打开 <code>cmake-gui.exe</code>,在第一行 <code>Where is the source code:</code> 右边选择你的 zlib 源码目录(有 <code>CMakeLists.txt</code> 文件的),在第三行 <code>Where to build the binaries:</code> 右边选择编译结果目录,随便放哪都行。</p>
<p>点击左下角 <code>Configure</code> 选择构建工具。MinGW 就选择 <code>MinGW Makefiles</code>。</p>
<p>注意下面有四个选项,它默认选第一项 <code>Use default native compilers</code>,但没用,请选择第二项 <code>Specify native compilers</code>,然后点击 <code>Next</code> 选择编译器路径。编译 C 语言的程序名是 <code>gcc.exe</code>,C++ 的是 <code>g++.exe</code>,Fortran 的是 <code>gfortran.exe</code>,自行找到相应程序即可。然后点击 <code>Finish</code>。</p>
<blockquote>
<p>如果选错了,点击 <code>Configure</code> 不能重新配置。可以在左上角的 <code>File -> Delete Cache</code> 清空缓存再重新配置。</p>
</blockquote>
<p>此时下面的日志一般会报错,关键词 <code>CMake was unable to find a build program corresponding to "MinGW Makefiles".</code> <code>CMAKE_MAKE_PROGRAM is not set.</code> 那就在上方的选项中搜索 <code>CMAKE_MAKE_PROGRAM</code> 并配置 <code>make.exe</code> 的路径即可。注意你可能需要在右上方勾选 <code>Grouped</code> 和 <code>Advanced</code> 以分组和显示更多选项。</p>
<p>点击 <code>Configure</code>,执行配置检查。检查完毕后上方会出现新的配置选项,包括 <code>CPACK</code> 和 <code>ZLIB</code> 等,按需选择。我需要 zip 功能,所以勾选 zip 相关的选项。</p>
<p>点击 <code>Generate</code>,开始生成。生成完毕后打开你选择的编译结果目录,在此处打开命令行执行 <code>make</code> 进行编译。<strong>编译完成即可得到 <code>libz.dll</code>。</strong></p>
<h2 id="2-编译-libzip">2. 编译 libzip</h2>
<p>在 https://libzip.org/download/ 下载 libzip 源码。在其根目录下同样有 <code>CMakeLists.txt</code> 文件。</p>
<p>打开 <code>cmake-gui.exe</code>,同上选择相关目录。</p>
<p>点击 <code>Configure</code> 会报错,关键词 <code>Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR)</code>。因为 libzip 依赖 zlib,所以必须在上方的选项中配置 <code>ZLIB</code> 相关的选项,包括 <code>ZLIB_INCLUDE_DIR</code>:zlib 源码目录,<code>ZLIB_LIBRARY_DEBUG</code> 和 <code>ZLIB_LIBRARY_RELEASE</code>:编译 zlib 得到的 <code>libz.dll</code>。</p>
<p>点击 <code>Generate</code>,开始生成。会出现 Warning,可以不用管,如果不想看到就在上方搜索相关选项关闭即可。生成完毕后同上执行 <code>make</code> 进行编译。<strong>编译完成即可在结果目录的 <code>lib</code> 目录下得到 <code>libzip.dll</code>。</strong></p>
<h2 id="3-使用-libzip">3. 使用 libzip</h2>
<p>这里给出一个测试用例 <code>demo.c</code>,功能是打开当前目录下的 <code>test.zip</code> 并解压其中的 <code>a.txt</code>:</p>
<blockquote>
<p>注意需要把 <code>zip.h</code>(在 libzip 源码的 <code>lib</code> 目录中)复制到程序所在目录,以及 <code>zip.h</code> 引用的 <code>zipconf.h</code>。</p>
</blockquote>
<pre><code class="language-c">#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zip.h"
int main(void) {
const char* zip_path = "test.zip";
const char* target_name = "a.txt";
const char* output_name = "a.txt";
zip_t* archive = NULL;// 打开的 ZIP 归档
zip_file_t* zf = NULL;// 打开的 ZIP 内文件
zip_stat_t sb; // 文件统计信息
zip_error_t error; // 错误对象
FILE* out_fp = NULL; // 输出文件指针
char buf; // 读缓冲区
zip_int64_t bytes_read;
size_t bytes_written;
zip_int64_t index;
int err = 0;
/* 1. 打开 ZIP 归档(只读模式) */
archive = zip_open(zip_path, ZIP_RDONLY, &err);
if (archive == NULL) {
zip_error_init_with_code(&error, err);
fprintf(stderr, "无法打开 ZIP 文件 '%s':%s\n", zip_path,
zip_error_strerror(&error));
zip_error_fini(&error);
return 1;
}
/* 2. 根据文件名查找在归档中的索引 */
index = zip_name_locate(archive, target_name, 0);
if (index < 0) {
fprintf(stderr, "ZIP 中未找到文件 '%s'\n", target_name);
zip_close(archive);
return 1;
}
/* 3. 获取文件信息(大小、CRC 等)——可选,但可用于进度显示 */
if (zip_stat_index(archive, index, 0, &sb) == 0) {
printf("正在解压 '%s',大小:%llu 字节\n", target_name,
(unsigned long long)sb.size);
}
/* 4. 打开 ZIP 内的目标文件 */
zf = zip_fopen_index(archive, index, 0);
if (zf == NULL) {
fprintf(stderr, "无法打开 ZIP 内的文件 '%s':%s\n", target_name,
zip_strerror(archive));
zip_close(archive);
return 1;
}
/* 5. 创建输出文件(二进制写模式) */
out_fp = fopen(output_name, "wb");
if (out_fp == NULL) {
fprintf(stderr, "无法创建输出文件 '%s':%s\n", output_name,
strerror(errno));
zip_fclose(zf);
zip_close(archive);
return 1;
}
/* 6. 循环读取 ZIP 内文件内容并写入磁盘 */
while ((bytes_read = zip_fread(zf, buf, sizeof(buf))) > 0) {
bytes_written = fwrite(buf, 1, (size_t)bytes_read, out_fp);
if (bytes_written != (size_t)bytes_read) {
fprintf(stderr, "写入文件失败(磁盘空间不足?)\n");
fclose(out_fp);
zip_fclose(zf);
zip_close(archive);
return 1;
}
}
/* 检查读取过程中是否发生错误 */
if (bytes_read < 0) {
fprintf(stderr, "读取 ZIP 内容时出错:%s\n", zip_file_strerror(zf));
fclose(out_fp);
zip_fclose(zf);
zip_close(archive);
return 1;
}
/* 7. 关闭所有句柄,释放资源 */
fclose(out_fp);
zip_fclose(zf);
zip_close(archive);
printf("成功解压 '%s' 到当前目录。\n", target_name);
return 0;
}
</code></pre>
<p>将 <code>libz.dll</code> 和 <code>libzip.dll</code> 复制到程序所在目录并编译:</p>
<pre><code class="language-bash">gcc demo.c libzip.dll -o demo.exe -Wall -Wextra
</code></pre>
<p>编译完成后运行 <code>demo.exe</code> 查看效果。<strong>注意程序所在目录中必须要有 <code>libz.dll</code> 和 <code>libzip.dll</code> 才能运行。</strong></p><br><br>
来源:https://www.cnblogs.com/uxod/p/19684600
頁:
[1]