c++解压各类格式压缩文件

本文介绍了如何使用C++通过unrar库解压RAR文件,以及利用libarchive库处理zip,7z,tar,rpm,jar等其他格式的解压,包括makefile中的链接设置和解压函数实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转发请注明出处!

本文介绍c++解压常见的各类压缩文件包括rar,zip,7z,gz,bz2,tar,rpm,jar
因为第三方库的原因,使用到了unrar,libarchive,libz,bzip2等几个库,所以需要先安装这几个库
这里不做介绍
1.解压rar

使用unrar进行解压,unrar我是源码编译,将编译好的libunrar.so放到自己的目录中去

#include "../lib/src/trans/unrar/rar1.hpp"  //需要引入rar1.hpp这个头文件,路径换成自己的

//这个是我处理解压后文件存放路径的
string getdst_path(char *src_filepath, const string &dst_path)
{
	char rar_filename[512] = { 0 };
	char *e_pos = strrchr(src_filepath, '/');
	if (e_pos != NULL) {
		strcpy(rar_filename, e_pos + 1);
	}
	else {
		strcpy(rar_filename, src_filepath);
	}
	char dst_filename[512] = { 0 };
	sprintf(dst_filename, "%s%s_#$1", dst_path.c_str(), rar_filename);
	printf("----------- 00 dst_filename = %s\n", dst_filename);
	return dst_filename;
}

int decompression_rarfile(char *rar_filepath, const char *dst_path)
{
	if (rar_filepath == NULL || dst_path == NULL) return -1;
	RAROpenArchiveDataEx archiveData;
	memset(&archiveData, 0, sizeof(archiveData));
	archiveData.ArcName = rar_filepath;
	archiveData.OpenMode = RAR_OM_EXTRACT;
	HANDLE hArcData = RAROpenArchiveEx(&archiveData);
	if (archiveData.OpenResult != 0)
	{
		return -1;
	}
	string dst_filename = getdst_path(rar_filepath, dst_path);
	RARHeaderDataEx headerData;
	memset(&headerData, 0, sizeof(headerData));
	int result;
	while ((result = RARReadHeaderEx(hArcData, &headerData)) == 0)
	{
		if (headerData.Flags & RHDF_DIRECTORY)
		{
			continue;  // 跳过目录
		}
		if (RARProcessFile(hArcData, RAR_EXTRACT, (char*)dst_filename.c_str(), NULL) != 0)
		{
			return -1;
		}
	}
	RARCloseArchive(hArcData);
	return 0;
}
在makefile 文件中要加入-lunrar
2.zip,7z,tar,rpm,jar格式的解压

这几个格式采用了libarchive这个第三方库进行解压,这个库支持很多格式的解压

libarchive可以解压jar包是jar采用了和zip一样的压缩算法
下面是archive.h中所包含的所有支持的格式和算法
__LA_DECL int archive_read_support_filter_all(struct archive *);
__LA_DECL int archive_read_support_filter_bzip2(struct archive *);
__LA_DECL int archive_read_support_filter_compress(struct archive *);
__LA_DECL int archive_read_support_filter_gzip(struct archive *);
__LA_DECL int archive_read_support_filter_grzip(struct archive *);
__LA_DECL int archive_read_support_filter_lrzip(struct archive *);
__LA_DECL int archive_read_support_filter_lz4(struct archive *);
__LA_DECL int archive_read_support_filter_lzip(struct archive *);
__LA_DECL int archive_read_support_filter_lzma(struct archive *);
__LA_DECL int archive_read_support_filter_lzop(struct archive *);
__LA_DECL int archive_read_support_filter_none(struct archive *);
__LA_DECL int archive_read_support_filter_program(struct archive *,
		     const char *command);
__LA_DECL int archive_read_support_filter_program_signature
		(struct archive *, const char * /* cmd */,
				    const void * /* match */, size_t);
__LA_DECL int archive_read_support_filter_rpm(struct archive *);
__LA_DECL int archive_read_support_filter_uu(struct archive *);
__LA_DECL int archive_read_support_filter_xz(struct archive *);
__LA_DECL int archive_read_support_filter_zstd(struct archive *);

__LA_DECL int archive_read_support_format_7zip(struct archive *);
__LA_DECL int archive_read_support_format_all(struct archive *);
__LA_DECL int archive_read_support_format_ar(struct archive *);
__LA_DECL int archive_read_support_format_by_code(struct archive *, int);
__LA_DECL int archive_read_support_format_cab(struct archive *);
__LA_DECL int archive_read_support_format_cpio(struct archive *);
__LA_DECL int archive_read_support_format_empty(struct archive *);
__LA_DECL int archive_read_support_format_gnutar(struct archive *);
__LA_DECL int archive_read_support_format_iso9660(struct archive *);
__LA_DECL int archive_read_support_format_lha(struct archive *);
__LA_DECL int archive_read_support_format_mtree(struct archive *);
__LA_DECL int archive_read_support_format_rar(struct archive *);
__LA_DECL int archive_read_support_format_rar5(struct archive *);
__LA_DECL int archive_read_support_format_raw(struct archive *);
__LA_DECL int archive_read_support_format_tar(struct archive *);
__LA_DECL int archive_read_support_format_warc(struct archive *);
__LA_DECL int archive_read_support_format_xar(struct archive *);
/* archive_read_support_format_zip() enables both streamable and seekable
 * zip readers. */
__LA_DECL int archive_read_support_format_zip(struct archive *);

如果只需要解压一种或者几种格式的,可以使用格式对应的具体函数,否则就可以用

    archive_read_support_filter_all(a);
    archive_read_support_format_all(a);

解压代码:

#include <archive.h>
#include <archive_entry.h>
//上面这两个头文件需要引入

int decompression_tar_zip_7z_file(char *input_file_path, const char *dst_path, int file_type, int file_size)
{
	struct archive* a;
    struct archive_entry* entry;

    a = archive_read_new();
    archive_read_support_filter_all(a);
    archive_read_support_format_all(a);
	int r = archive_read_open_filename(a, input_file_path, file_size);
    if ((r != ARCHIVE_OK)) {
        return r;
    }
	string dst_filename = getdst_path(input_file_path, dst_path);

    while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
		//获取压缩文件条目的路径。
        const char* entryPath = archive_entry_pathname(entry);
        std::string destPath = dst_filename + "/" + entryPath;
		//设置解压缩后的文件路径。
        archive_entry_set_pathname(entry, destPath.c_str());
		r = archive_read_extract(a, entry, ARCHIVE_EXTRACT_TIME);
        if ((r != ARCHIVE_OK)) {
            return r;
        }
    }
    archive_read_close(a);
    archive_read_free(a);
    return 0;
}
makefile 加入 -larchive
3.解压gz格式
gz格式只支持单个文件的压缩,对于gz格式,我尝试了在linux下的解压,发现不能破坏其默认打包名字,重命名会破坏原有文件名称,例如我的文件名称是001.txt.gz,我重名为001.gz,那么用命令解压得到的文件名称就是001,没有txt的后缀。但是在windows下,用7z工具打开文件,却能看到子文件的真实名称,这里后面在研究下。
#include <zlib.h>
#include <boost/filesystem.hpp>
//需要引入这两个

int decompress_GzipFile(const std::string& gzipFilePath , const std::string& extractPath,bool first) {
    gzFile gzFile = gzopen(gzipFilePath.c_str(), "rb");
    if (gzFile == nullptr) {
        return -1;
    }
	string dst_path = getdst_path((char*)gzipFilePath.c_str(),extractPath);
    if (access(dst_path.c_str(), F_OK))
    {
        if (!boost::filesystem::create_directories(dst_path))
        {
            return -1;
        }
    }
	// 获取压缩文件的名称
	int pos = -1;
	string src_tarfileName;
	if(first)
	{
        //$1 是文件路径中我自己添加的路径分割标识
		pos = gzipFilePath.rfind("$1");
    	src_tarfileName = gzipFilePath.substr(pos+4,gzipFilePath.length()-pos -5);  //-7是去除$1和.gz扩展名
	}
	else
	{
		pos = gzipFilePath.rfind("/");
    	src_tarfileName = gzipFilePath.substr(pos,gzipFilePath.length()-pos -1);  //-1是去除$1和.gz扩展名
	}
    // cout<<"------ src_tarfileName = "<<src_tarfileName<<","<<src_tarfileName.length()<<endl;
    // 循环解压缩每个文件
    char buffer[16384];
    int uncompressedBytes;
    std::string currentFileName;
    while ((uncompressedBytes = gzread(gzFile, buffer, sizeof(buffer))) > 0) {
        // 如果还没有设置当前文件的名称,则读取压缩文件的原始名称
        if (currentFileName.empty()) {
            currentFileName = dst_path + "/" + src_tarfileName;
        }
		// cout<< "------currentFileName = "<<currentFileName<<endl;
        // 解压缩数据写入目标文件
        std::ofstream outFile(currentFileName, std::ios::binary | std::ios::app);
        if (!outFile) {
            gzclose(gzFile);
            return -1;
        }
        outFile.write(buffer, uncompressedBytes);
        outFile.close();
        // 如果已经读取完一个文件,则重置当前文件名称用于解压缩下一个文件
        if (gzeof(gzFile)) {
            currentFileName.clear();
        }
    }
    // 关闭压缩文件
    gzclose(gzFile);
    return 0;
}
makefile 添加-lz
4.解压bz2格式
bz2格式和gz格式一样,只支持单个文件的压缩,重命名会破坏原有文件名称
#include <cerrno>
#include <boost/filesystem.hpp>
#include "../include/bzlib.h"  //bzip2是编译的源码,这里是我把bzlib.h添加到了一个路径中,你要替换成自己的

int decompressBz2File2(const std::string& inputFilePath, const std::string& outputDirectory) {
   FILE* inputFile = fopen(inputFilePath.c_str(), "rb");
    if (!inputFile) {
        std::cerr << "Failed to open input file: " << inputFilePath << std::endl;
        return -1;
    }

    BZFILE* bzip2File = BZ2_bzReadOpen(nullptr, inputFile, 0, 0, nullptr, 0);
    if (bzip2File == nullptr) {
        std::cerr << "Failed to open bzip2 file: " << inputFilePath << std::endl;
        fclose(inputFile);
        return -1;
    }
    // 获取压缩文件的名称
	int pos = -1;
	string src_fileName;
	if(true)
	{
		pos = inputFilePath.rfind("$1");
    	src_fileName = inputFilePath.substr(pos+4,inputFilePath.length()-pos -6);  
	}
	else
	{
		pos = inputFilePath.rfind("/");
    	src_fileName = inputFilePath.substr(pos,inputFilePath.length()-pos -2); 
	}
    cout<<"------ src_tarfileName = "<<src_fileName<<","<<src_fileName.length()<<endl;
    std::string outputFileDir = getdst_path((char*)inputFilePath.c_str(),outputDirectory);
    if (access(outputFileDir.c_str(), F_OK))
    {
        if (!boost::filesystem::create_directories(outputFileDir))
        {
            printf("---- create target path fail, %s, error = %s \n", outputFileDir.c_str(), strerror(errno));
            return -1;
        }
    }
    std::string outputFilePath = outputFileDir + "/" + src_fileName;
    // 创建目标文件夹(如果不存在)
    cout<< "------  outputFilePath = "<<outputFilePath<<endl;
    char buffer[4096];
    std::ofstream outputFileStream;
    outputFileStream.open(outputFilePath, std::ios::out | std::ios::binary);
    if (!outputFileStream.is_open()) {
        std::cerr << "Failed to open output file,error =" << strerror(errno) << std::endl;
        BZ2_bzReadClose(nullptr, bzip2File);
        fclose(inputFile);
        return -1;
    }
    int bzerror, bytesRead;
    /*从压缩文件b读取最多len(未压缩)字节到缓冲区buf。如果读取成功,则
    bzerror设置为BZ_OK,并返回读取的字节数。如果检测到逻辑流结
    束,bzerror将被设置为BZ_STREAM_END,并返回读取的字节数。所有其
    他bzerror值表示错误。
    */
    while ((bytesRead = BZ2_bzRead(&bzerror, bzip2File, buffer, 4096)) > 0) {
        outputFileStream.write(buffer, bytesRead);
    }
    BZ2_bzReadClose(nullptr, bzip2File);
    fclose(inputFile);
    outputFileStream.close();
    return 0;
}
makefile 要加入-lbz2

参考文档【从0到1了解Libarchive】Libarchive的用途意义以及成功入门Libarchive_libarchive编译-CSDN博客

 bzip2 and libbzip2, version 1.0.8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值