使用libzip压缩文件和文件夹

简介: 使用libzip压缩文件和文件夹

使用libzip压缩文件和文件夹

简单说说自己遇到的坑:

  1. 分清楚三个组件:zlib、minizip和libzip。zlib是底层和最基础的C库,用于使用Deflate算法压缩和解压缩文件流或者单个文件,但是如果要压缩文件夹就很麻烦,主要是不知道如何归档,在zip内部形成对应的目录。这时就需要用更高级别的库,也就是minizip或libzip。
  2. minizip、libzip随着版本迭代接口一直变化,我连续使用了通义千问、文心一言、gemini三个AI,基本上没给出能使用的代码,主要是函数接口总是不对,或者参数多了或者少了。像这种情况就不要再参考AI给出的答案了,赶紧翻官方文档才是正经。
  3. minizip和libzip都是基于zlib实现的,都尝试使用过,感觉还是libzip的接口设计更清晰一点,官方文档说明也还不错。
  4. 压缩文件夹的功能需要借助于操作文件系统的库来组织zip内部的归档目录,我这里使用的是C++17的std::filesystem。

具体代码实现如下:

#include <zip.h>
#include <filesystem>
#include <fstream>
#include <iostream>
using namespace std;
void CompressFile2Zip(std::filesystem::path unZipFilePath,
                      const char* relativeName, zip_t* zipArchive) {
  std::ifstream file(unZipFilePath, std::ios::binary);
  file.seekg(0, std::ios::end);
  size_t bufferSize = file.tellg();
  char* bufferData = (char*)malloc(bufferSize);
  file.seekg(0, std::ios::beg);
  file.read(bufferData, bufferSize);
  //第四个参数如果非0,会自动托管申请的资源,直到zip_close之前自动销毁。
  zip_source_t* source =
      zip_source_buffer(zipArchive, bufferData, bufferSize, 1);
  if (source) {
    if (zip_file_add(zipArchive, relativeName, source, ZIP_FL_OVERWRITE) < 0) {
      std::cerr << "Failed to add file " << unZipFilePath
                << " to zip: " << zip_strerror(zipArchive) << std::endl;
      zip_source_free(source);
    }
  } else {
    std::cerr << "Failed to create zip source for " << unZipFilePath << ": "
              << zip_strerror(zipArchive) << std::endl;
  }
}
void CompressFile(std::filesystem::path unZipFilePath,
                  std::filesystem::path zipFilePath) {
  int errorCode = 0;
  zip_t* zipArchive = zip_open(zipFilePath.generic_u8string().c_str(),
                               ZIP_CREATE | ZIP_TRUNCATE, &errorCode);
  if (zipArchive) {
    CompressFile2Zip(unZipFilePath, unZipFilePath.filename().string().c_str(),
                     zipArchive);
    errorCode = zip_close(zipArchive);
    if (errorCode != 0) {
      zip_error_t zipError;
      zip_error_init_with_code(&zipError, errorCode);
      std::cerr << zip_error_strerror(&zipError) << std::endl;
      zip_error_fini(&zipError);
    }
  } else {
    zip_error_t zipError;
    zip_error_init_with_code(&zipError, errorCode);
    std::cerr << "Failed to open output file " << zipFilePath << ": "
              << zip_error_strerror(&zipError) << std::endl;
    zip_error_fini(&zipError);
  }
}
void CompressDirectory2Zip(std::filesystem::path rootDirectoryPath,
                           std::filesystem::path directoryPath,
                           zip_t* zipArchive) {
  if (rootDirectoryPath != directoryPath) {
    if (zip_dir_add(zipArchive,
                    std::filesystem::relative(directoryPath, rootDirectoryPath)
                        .generic_u8string()
                        .c_str(),
                    ZIP_FL_ENC_UTF_8) < 0) {
      std::cerr << "Failed to add directory " << directoryPath
                << " to zip: " << zip_strerror(zipArchive) << std::endl;
    }
  }
  for (const auto& entry : std::filesystem::directory_iterator(directoryPath)) {
    if (entry.is_regular_file()) {
      CompressFile2Zip(
          entry.path().generic_u8string(),
          std::filesystem::relative(entry.path(), rootDirectoryPath)
              .generic_u8string()
              .c_str(),
          zipArchive);
    } else if (entry.is_directory()) {
      CompressDirectory2Zip(rootDirectoryPath, entry.path().generic_u8string(),
                            zipArchive);
    }
  }
}
void CompressDirectory(std::filesystem::path directoryPath,
                       std::filesystem::path zipFilePath) {
  int errorCode = 0;
  zip_t* zipArchive = zip_open(zipFilePath.generic_u8string().c_str(),
                               ZIP_CREATE | ZIP_TRUNCATE, &errorCode);
  if (zipArchive) {
    CompressDirectory2Zip(directoryPath, directoryPath, zipArchive);
    errorCode = zip_close(zipArchive);
    if (errorCode != 0) {
      zip_error_t zipError;
      zip_error_init_with_code(&zipError, errorCode);
      std::cerr << zip_error_strerror(&zipError) << std::endl;
      zip_error_fini(&zipError);
    }
  } else {
    zip_error_t zipError;
    zip_error_init_with_code(&zipError, errorCode);
    std::cerr << "Failed to open output file " << zipFilePath << ": "
              << zip_error_strerror(&zipError) << std::endl;
    zip_error_fini(&zipError);
  }
}
int main() {
  //压缩文件
  //CompressFile("C:/Data/Builder/Demo/view.tmp", "C:/Data/Builder/Demo/view.zip");
  //压缩文件夹
  CompressDirectory("C:/Data/Builder/Demo", "C:/Data/Builder/Demo.zip");
  return 0;
}
CPP 折叠 复制 全屏

关于使用的libzip,有以下几点值得注意:

  1. libzip压缩的zip内部的文件名默认采用UTF-8编码。
  2. libzip要求使用正斜杠 ('/') 作为目录分隔符。
  3. libzip操作不同的zip线程安全,操作同一个zip线程不安全。
  4. zip_source_buffer这个函数的接口的第四个参数如果非0,会自动托管申请的资源。官方文档提到需要保证传入zip_source_buffer的数据资源需要保证跟zip_source_t一样的声明周期,但是笔者经过测试,正确的行为应该是传入zip_source_buffer的数据资源需要保证调用zip_close之前都有效,否则就有问题。

分类: C++ , 基础组件

标签: C/C++ , 压缩 , libzip

相关文章
|
Linux
一个进程最多可以创建多少个线程基本分析
一个进程最多可以创建多少个线程基本分析
1161 1
|
Windows
Qt5.14.2 轻松掌握Qt中的压缩与解压缩:QuaZIP的神秘面纱与实战演练之使用QuaZIP
Qt5.14.2 轻松掌握Qt中的压缩与解压缩:QuaZIP的神秘面纱与实战演练之使用QuaZIP
856 0
|
SQL Java 数据库连接
SpringBoot2.x系列教程31--SpringBoot整合H2内存数据库实现CRUD操作
前言 在上一章节中,我给大家详细讲解了H2数据库的安装配置,接下来我就带大家在Spring Boot中整合H2数据库,实现代码操作。 一. 以内嵌模式整合H2数据库 1. 创建Web项目 我们按照之前的经验,创建一个SpringBoot的Web程序,具体过程略,请参考下图创建。 2. 添加依赖包 然后在pom.xml文件中添加如下依赖包。 <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <de
2483 1
SpringBoot2.x系列教程31--SpringBoot整合H2内存数据库实现CRUD操作
|
存储 SQL 缓存
Apache Doris & SelectDB 技术能力全面解析
本文将对 Doris & SelectDB 适合的分析场景和技术能力进行概述解析
2197 1
Apache Doris & SelectDB 技术能力全面解析
|
开发框架 Java 关系型数据库
Java毕业论文参考文献参考例子整理
Java毕业论文参考文献参考例子整理
1004 0
|
Web App开发 监控 JavaScript
一些常用的 Vue 性能分析工具
【10月更文挑战第2天】
1282 154
|
Python
【Python】已解决:ValueError: Worksheet named ‘Sheet’ not found
【Python】已解决:ValueError: Worksheet named ‘Sheet’ not found
1797 0
C#基础③——类型转换(int转double、double转int、Convert)
不同数据类型间的转换,如:将int类型转换为string类型
|
机器学习/深度学习 PyTorch 算法框架/工具
使用BatchNorm替代LayerNorm可以减少Vision Transformer训练时间和推理时间
本文探讨了在Vision Transformer (ViT)架构中采用批量归一化(BatchNorm)替代层归一化(LayerNorm)的影响。ViT以其在计算机视觉领域的优异表现而闻名,但存在训练耗时长及对小型数据集推理速度慢的问题。文章提出两种改进模型:ViTBNFFN,在前馈网络中加入BatchNorm;ViTBN,则全面替换为BatchNorm。
572 1
使用BatchNorm替代LayerNorm可以减少Vision Transformer训练时间和推理时间
|
计算机视觉
HDR的主要标准有哪些?
HDR(高动态范围)技术通过提供更广阔的亮度范围和丰富的色彩细节,显著提升图像质量,使电影、图片和游戏画面更加逼真。相比SDR,HDR拥有更宽的色域、更高的色深和动态范围,支持多种行业标准如HDR10、Dolby Vision、HDR10+、HLG和HDR Vivid,为用户带来更接近真实的视觉体验。

热门文章

最新文章