【C++】libzip
压缩
zip_open创建zip文件,返回zip_t*。zip_source_file打开文件为一个source,返回zip_source_t*。zip_file_add把source添加到zip实现把文件添加到zip,返回zip_int64_t。错误时返回-1,调用zip_source_free(source)释放source。zip_close关闭zip文件。
/*
* 打包压缩文件
*/
#include <stdlib.h>
#include <zip.h>
struct fileNode
{
string fileName;//文件名
fs::path filePath;//文件路径
};
//zipPath形如/tmp/666.zip
//isRandomSuffix=true表示加上随机后缀生成临时文件,此时zipPath中路径将被改为加上后缀后的路径
//isRandomSuffix=false表示直接使用传入路径作为zip路径
tl::expected<bool, string> packZip(const vector<fileNode>& fileList, string* zipPath, bool addRandomSuffix)
{
//入参判断
if(fileList.size()==0 || zipPath==nullptr)
return tl::make_unexpected(string("入参非法"));
bool failure = false;
int filesAddZipCount = 0; //成功添加到zip中的文件数
string zipPathSuffix = ".XXXXXX";
string zipPathTmpStr = *zipPath + zipPathSuffix;
char* zipPath_;//最后使用的zip路径
if(addRandomSuffix)
{
*zipPath = zipPathTmpStr;
memset(zipPath_, zipPathTmpStr.c_str(), zipPathTmpStr.size());
zipPath_ = zipPathTmpStr.c_str(); //char zipName[] = "/tmp/hzisemt.zip.XXXXXX";
int fd = mkstemp64(zipPath_);//mkstemp64会根据替换zipName中的XXXXXX为随机数字并创建临时文件,返回该文件的描述符
close(fd); //调用方通过zip文件名访问,不通过fd读写
}
else
{
zipPath_ = zipPath->c_str();
}
//创建zip文件
zip_t* z = zip_open(zipPath_, ZIP_CREATE | ZIP_TRUNCATE, nullptr);
if (!z)
return tl::make_unexpected(string("zip_open failed") + );
//遍历文件下载列表
for (auto file : files)
{
//打开文件为一个source(把source添加到zip中实现添加文件到zip)
zip_source_t* source = zip_source_file(z, file.filePath.c_str(), 0, 0);
if (!source)
{
if (fs::exists(zipPath_))
remove(zipPath_); //打包失败,把生成的zip删除
return tl::make_unexpected(string("zip_source_file failed"));
}
//把source添加到zip中,并返回该文件在zip中的index
zip_int64_t index = zip_file_add(z, file.fileName.c_str(), source, ZIP_FL_ENC_RAW);
if (-1 == index/* || -1 == zip_set_file_compression(z, index, ZIP_CM_STORE, 0)*/)
{
zip_source_free(source);//index=-1,文件保存失败,释放source,跳出循环终止后续文件的添加
if (fs::exists(zipPath_))
remove(zipPath_);
return tl::make_unexpected(string("zip_file_add failed"));
}
++filesAddZipCount;//成功添加文件数+1
}
if (zip_close(z) == -1) //文件添加完毕,关闭zip
{
if (fs::exists(zipPath_))
remove(zipPath_);
return tl::make_unexpected(string("zip_close failed"));
}
if (filesAddZipCount == 0) //zip内没文件
{
if (fs::exists(zipPath_))
remove(zipPath_);
return tl::make_unexpected(string("zip为空!"));
}
return true;
}
解压缩
-
使用
zip_open打开一个压缩文件,并使用zip_get_num_entries获取压缩文件中的条目数。 -
遍历每个条目,使用
zip_stat_index获取条目的基本信息。 -
使用
zip_fopen_index打开条目,使用zip_fread读取其中的数据,并将解压后的数据写入本地文件。
/*
* 解压缩,返回文件名列表
*/
#include <zip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
vector<string>& unPackZip(string zipPath, string zipUnPackPath)
{
int err = 0;
struct zip* zipfile = zip_open(zipPath.c_str(), ZIP_CHECKCONS, &err);
if (!zipfile)
{
printf("zip open failed: %d\n", err);
return 1;
}
zip_int64_t num_entries = zip_get_num_entries(zipfile, 0);
for (zip_int64_t i = 0; i < num_entries; i++)
{
struct zip_stat stat;
zip_stat_index(zipfile, i, 0, &stat);
printf("the file name is: %s\n", stat.name);
struct zip_file *entry = zip_fopen_index(zipfile, i, 0);
if (!entry)
{
printf("fopen index failed\n");
continue;
}
FILE *fp = fopen(stat.name, "w+");
if (!fp)
{
printf("create local file failed\n");
zip_fclose(entry);
continue;
}
char buf[1024];
zip_int64_t len = 0;
while (len < stat.size)
{
int read = zip_fread(entry, buf, sizeof(buf));
if (read < 0) {
printf("read file failed\n");
break;
}
fwrite(buf, 1, read, fp);
len += read;
}
fclose(fp);
zip_fclose(entry);
}
zip_close(zipfile);
return 0;
}

浙公网安备 33010602011771号