首页 > 其他分享 >使用libzip压缩文件和文件夹

使用libzip压缩文件和文件夹

时间:2024-07-12 23:19:39浏览次数:7  
标签:std zip 压缩文件 source 文件夹 libzip file include

简单说说自己遇到的坑:

  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;
}

关于使用的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之前都有效,否则就有问题。

标签:std,zip,压缩文件,source,文件夹,libzip,file,include
From: https://www.cnblogs.com/charlee44/p/18299531

相关文章

  • php:访问/tmp文件夹中文件会报错:file does not exist
    一,php访问/tmp文件夹中文件会报错:代码:$filePath="/tmp/php-temp/keji.jpeg";$is_ex=file_exists($filePath);//print_r("is_ex:".$is_ex);if($is_ex){echo"文件".$filePath.&......
  • 如何强制删除文件夹
    前几天下载了ZeroTier,不知道是哪里出问题了,手动删除文件夹一直不成功,一直提示“你需要xxx权限才能删除改文件夹”,就算我修改了文件夹所有者有无济于事,在网上找了很多方法都没用,比如说“shift+del”,还是会提示我权限不够后面找到一个方法终于解决了每次删文件都提示没有管理员权......
  • 压缩文件的解析方式
            我们常用的压缩文件有两种:后缀为.zip或者.rar,接下来将介绍解析两种压缩文件的代码。需要用到三个jar包:commons-io-2.16.1.jar、junrar-7.5.5.jar、slf4j-api-2.0.13.jar,可以在官网下载,也可以发私信。        这段代码是一个Java程序,包含了一个main方......
  • 使用Java IO进行压缩文件的解析方式
    JavaIO库提供了对ZIP解压缩的支持,主要通过java.util.zip包中的类来实现。ZipEntry:表示ZIP文件中的一个条目,可以是文件或目录。ZipInputStream:用于进行zip格式的压缩文件输入流。ZipOutputStream:用于进行zip格式的压缩文件输出流。对ZIP格式的文件进行解压      ......
  • 如何处理压缩文件de方式总结!!!
    目录1.Java标准库中的压缩相关API2.解压缩过程3.第三方库4.使用第三方库的步骤5.参考代码1.Java标准库中的压缩相关APIJava的标准库java.util.zip提供了处理ZIP和GZIP格式压缩文件的功能。这个包包含以下主要类:(1)ZipFile:用于读取ZIP文件的元数据,如文件列表和注......
  • 批量处理文件夹内的所有图片
    本章将介绍如何对我们文件夹中的图片进行批量处理,也就是批量进行SVD分解,当然这本质上也是一个循环的过程。但如何实现该循环,如何利用matlab批量读取文件进行处理,这是我们本章要体现的重点思想目录一、找到文件路径与提取文件信息二、进行循环,批量处理图片文件一、找到文件路径与......
  • 如何保护重要文件夹?文件夹保护方法盘点
    文件夹是管理电脑数据的重要工具,为了避免文件夹数据泄露,我们需要保护重要文件夹。下面我们就来盘点一下文件夹的保护方法。文件夹加密超级大师文件夹加密超级大师是一款专业的电脑数据保护软件,支持文件夹加密、文件夹伪装、万能锁等功能,可以为文件夹提供全方位的保护。文......
  • 解锁:掌握:公网共享文件夹的关键技巧
    #前言#信息的快速共享和高效协作成为了各行各业发展的关键。公网共享文件夹作为一种便捷的信息共享方式,在教育培训、企业工作等领域发挥着重要作用。然而,要充分发挥公网共享文件夹的优势,掌握关键技巧至关重要。在这一过程中,江苏神卓旗下的一款创新产品为我们提供了卓越的解决......
  • opencv读取视频文件夹内视频的名字_时长_帧率_分辨率写入excel-cnblog
    看视频的时候有的视频文件名贼长。想要翻看,在文件夹里根本显示不出来,缩短又会丢失一些信息,所以我写了一份Python代码,直接获取视频的名字,时长,帧率,还有分辨率写到excel里。实际效果如下图。可以看到需要的大致信息都被提取出来了接下来直接上代码importosimportxlsxwr......
  • 创建vue-cli脚手架项目 和各个文件夹用途(最全面)
    一、安装Vue脚手架1、第一步(仅第一次执行):全局安装@vue/cli npmi@vue/cli-g2、切换到要创建项目的目录,然后创建项目vuecreatehellocli3、 进入项目 cdhellocli4、启动项目npmrunserve(默认一般是可从package.json→scripts下查看 )二、vue-cli脚手架初......