简单说说自己遇到的坑:

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

使用libzip压缩文件和文件夹的更多相关文章

  1. 【C#公共帮助类】WinRarHelper帮助类,实现文件或文件夹压缩和解压,实战干货

    关于本文档的说明 本文档使用WinRAR方式来进行简单的压缩和解压动作,纯干货,实际项目这种压缩方式用的少一点,一般我会使用第三方的压缩dll来实现,就如同我上一个压缩类博客,压缩的是zip文件htt ...

  2. C#文件或文件夹压缩和解压方法(通过ICSharpCode.SharpZipLib.dll)

    我在网上收集一下文件的压缩和解压的方法,是通过ICSharpCode.SharpZipLib.dll 来实现的 一.介绍的目录 第一步:下载压缩和解压的 ICSharpCode.SharpZipLib ...

  3. 关于SharpZipLib压缩分散的文件及整理文件夹的方法

    今天为了解决压缩分散的文件时,发现想通过压缩对象直接进行文件夹整理很麻烦,因为SharpZipLib没有提供压缩进某个指定文件夹的功能,在反复分析了SharpZipLib提供的各个接口方法后,终于找到 ...

  4. Python(文件、文件夹压缩处理模块,shelve持久化模块,xml处理模块、ConfigParser文档配置模块、hashlib加密模块,subprocess系统交互模块 log模块)

    OS模块 提供对操作系统进行调用的接口 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname")  改变当前脚本工作目 ...

  5. C#压缩、解压缩文件(夹)(rar、zip)

    主要是使用Rar.exe压缩解压文件(夹)(*.rar),另外还有使用SevenZipSharp.dll.zLib1.dll.7z.dll压缩解压文件(夹)(*.zip).需要注意的几点如下: 1.注 ...

  6. 使用ICSharpZipLib将文件夹压缩为zip文件

    序言:     在我接触Git和SVN之前,我最常用的保存数据的办法就是把文件夹压缩成一个zip文件,添加上时间戳.下面是我在学习C#的文件操作之后做的一个练习,使用开源的ICSharpZipLib来 ...

  7. java.util.zip压缩打包文件总结一:压缩文件及文件下面的文件夹

    一.简述 zip用于压缩和解压文件.使用到的类有:ZipEntry  ZipOutputStream 二.具体实现代码 package com.joyplus.test; import java.io ...

  8. java压缩指定目录下的所有文件和文件夹的代码

    将代码过程较好的代码段备份一下,下边资料是关于java压缩指定目录下的所有文件和文件夹的代码,希望对码农有帮助. String sourceDir="E:\test";int pa ...

  9. java压缩文件或文件夹并导出

    java压缩文件或文件夹并导出 tozipUtil: package com.zhl.push.Utils; import java.io.File; import java.io.FileInput ...

  10. 【转载】.NET压缩/解压文件/夹组件

    转自:http://www.cnblogs.com/asxinyu/archive/2013/03/05/2943696.html 阅读目录 1.前言 2.关于压缩格式和算法的基础 3.几种常见的.N ...

随机推荐

  1. 版本管理工具 nvm WIN版

    nvm -h //查看nvm的指令 nvm list //查看本地已经安装的node版本列表 nvm list available //查看可以安装的node版本 nvm install latest ...

  2. PageOffice 在线打开 word 文件并添加水印

    一.服务器端方法插入水印 1.插入文字水印 WordDocument doc = new WordDocument(); //添加水印 ,设置水印的内容 doc.getWaterMark().setT ...

  3. 【漏洞复现】金蝶OA-EAS系统 uploadLogo.action 任意文件上传漏洞(0day)

    阅读须知         此文所提供的信息只为网络安全人员对自己所负责的网站.服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作.利用此文所提供的 ...

  4. linux基础之awk命令详解

    一 awk主要是用来对指定对文本或者命令的输出逐行处理和分析的,下面来简单的看一下awk用法,方便以后需要使用的时候在回头看 1.1   基础的用法 [root@wxm ~]# cat test 1 ...

  5. kubernetes configmap配置方法

    configmap解释 在k8s运行期间会有一些依赖的配置文件,他们存在宿主机中的一个目录中或者代码里,如果配置放生变化,pod在另一台服务器启动,在没有这些配置的时候,可能会导致pod无法正常运行, ...

  6. Windows文件管理优化-实用电脑软件(一)

    RX文件管理器 (稀奇古怪的小软件,我推荐,你点赞!) 日后更新涉及:电脑.维护.清理.小工具.手机.APP.IOS.从WEB.到到UI.从开发,设计:诚意寻找伙伴(文编类.技术类.思想类)共编,共进 ...

  7. 蓝屏rtux64w10.sys

    蓝屏rtux64w10.sys 环境: WIN10 +  Realtek USB RTL8156B 2.5G网卡 表现: 局域网复制时,间隔性速度变为0,多次后,最终蓝屏. 解决方法: 更新驱动. 地 ...

  8. java.lang.NoClassDefFoundError: com/google/gson/GsonBuilder

    Exception in thread "main" java.lang.NoClassDefFoundError: com/google/gson/GsonBuilder 解决方 ...

  9. vmware 和 hyper-v不兼容,此主机不支持64位客户机操作系统

    在控制面板中关闭hyper-v功能后,仍然提示此主机不支持64位客户机操作系统. 解决方法: 需要在开始按钮 - 右键  -打开Windows PowerShell(管理员). 输入: bcdedit ...

  10. Spring源码——ConfigurationClassPostProcessor类

    引言 Spring容器中提供很多方便的注解供我们在工作中使用,比如@Configuration注解,里面可以在方法上定义@Bean注解,将调用方法返回的对象交由Bean容器进行管理,那么Spring框 ...