【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;
}
posted @ 2025-04-30 13:28  仰望星河Leon  阅读(97)  评论(0)    收藏  举报