博客 / 詳情

返回

[Windows/C] libzip 的編譯和使用

本文參考:

  • Windwos zlib 下載和編譯
  • Windwos 編譯 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 進行編譯。編譯完成即可得到 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 才能運行。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.