Loading

[Windows/C] libzip 的编译和使用

本文参考:

0. 准备工作

编译器:我使用的编译器是 gcc(MinGW),此时需将编译器目录下的 mingw32-make.exe 改名为 make.exe,方便使用。

你需要 CMake,可以在 https://cmake.org/download/ 下载。下载解压后在 bin 目录下找到 cmake-gui.exe,我们使用的是这个 GUI 程序。cmake.exe 是它的命令行版本,不建议直接使用。

1. 编译 zlib

libzip 依赖 zlib,所以你需要先编译 zlib。

先在 https://www.zlib.net/ 下载 zlib 源码,下载链接大概在

The current release is publicly available here:

这一行下面。可以看到在其根目录下有 CMakeLists.txt 文件。

打开 cmake-gui.exe,在第一行 Where is the source code: 右边选择你的 zlib 源码目录(有 CMakeLists.txt 文件的),在第三行 Where to build the binaries: 右边选择编译结果目录,随便放哪都行。

点击左下角 Configure 选择构建工具。MinGW 就选择 MinGW Makefiles

注意下面有四个选项,它默认选第一项 Use default native compilers,但没用,请选择第二项 Specify native compilers,然后点击 Next 选择编译器路径。编译 C 语言的程序名是 gcc.exe,C++ 的是 g++.exe,Fortran 的是 gfortran.exe,自行找到相应程序即可。然后点击 Finish

如果选错了,点击 Configure 不能重新配置。可以在左上角的 File -> Delete Cache 清空缓存再重新配置。

此时下面的日志一般会报错,关键词 CMake was unable to find a build program corresponding to "MinGW Makefiles". CMAKE_MAKE_PROGRAM is not set. 那就在上方的选项中搜索 CMAKE_MAKE_PROGRAM 并配置 make.exe 的路径即可。注意你可能需要在右上方勾选 GroupedAdvanced 以分组和显示更多选项。

点击 Configure,执行配置检查。检查完毕后上方会出现新的配置选项,包括 CPACKZLIB 等,按需选择。我需要 zip 功能,所以勾选 zip 相关的选项。

点击 Generate,开始生成。生成完毕后打开你选择的编译结果目录,在此处打开命令行执行 make 进行编译。编译完成即可得到 libz.dll

2. 编译 libzip

https://libzip.org/download/ 下载 libzip 源码。在其根目录下同样有 CMakeLists.txt 文件。

打开 cmake-gui.exe,同上选择相关目录。

点击 Configure 会报错,关键词 Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR)。因为 libzip 依赖 zlib,所以必须在上方的选项中配置 ZLIB 相关的选项,包括 ZLIB_INCLUDE_DIR:zlib 源码目录,ZLIB_LIBRARY_DEBUGZLIB_LIBRARY_RELEASE:编译 zlib 得到的 libz.dll

点击 Generate,开始生成。会出现 Warning,可以不用管,如果不想看到就在上方搜索相关选项关闭即可。生成完毕后同上执行 make 进行编译。编译完成即可在结果目录的 lib 目录下得到 libzip.dll

3. 使用 libzip

这里给出一个测试用例 demo.c,功能是打开当前目录下的 test.zip 并解压其中的 a.txt

注意需要把 zip.h(在 libzip 源码的 lib 目录中)复制到程序所在目录,以及 zip.h 引用的 zipconf.h

#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[8192];         // 读缓冲区
  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;
}

libz.dlllibzip.dll 复制到程序所在目录并编译:

gcc demo.c libzip.dll -o demo.exe -Wall -Wextra

编译完成后运行 demo.exe 查看效果。注意程序所在目录中必须要有 libz.dlllibzip.dll 才能运行。

posted @ 2026-03-08 01:50  UXOD  阅读(7)  评论(0)    收藏  举报