C 压缩和解压文件

libarchive

Windows下编译 libarchive

  1. CMake 直接使用默认值 Configure->Generate (默认支持rar,不支持zip)
    在这里插入图片描述
  2. 根据自己实际需求安装对应的依赖库,eg:BZIP2
  3. CMake 会出现waring,可以直接忽略
  4. 整体编译会运行test,时间很长。可以只选择编译libarchive

引入 zlib支持zip

在这里插入图片描述

如果需要MT模块同步调整ssl

在这里插入图片描述

引入zstd,for ZIPX

在这里插入图片描述

libarchive 解压文件

# 如果使用MT静态库,增加预定义宏:
LIBARCHIVE_STATIC
ZLIB_WINAPI

#需要引入库
archive.lib
zlibstaticd.lib
libssl64MTd.lib
libcrypto64MTd.lib
XmlLite.lib
libzstd_static.lib
  1. 如果存在中文需使用wchar或者utf-8否则会解压失败
#include "archive.h"
#include "archive_entry.h"
#include "StringUtil.h"
#include "FileUtil.h"
bool UnZipPack(const std::wstring& arPath, const std::wstring& outputDir, unzip_progress progress)
	{
		std::string UnZipTrackID = jeflib::StringUtil::UUIDString();
		XLOGI("UnZipPack[%s] begin,arPath[%s] outputDir[%s]", UnZipTrackID.c_str(), W2ACSTR(arPath), W2ACSTR(outputDir));
		struct archive* ar = archive_read_new();
		archive_read_support_format_all(ar); // 支持所有格式
		archive_read_support_filter_all(ar); // 支持所有压缩算法
		archive_read_set_options(ar, "charset=UTF-8");
		int nerr = archive_read_open_filename_w(ar, arPath.c_str(), 10240);
		if (nerr != ARCHIVE_OK) {
			XLOGW("UnZipPack[%s] failed,archive_read_open_filename_w err:%d", UnZipTrackID.c_str(), nerr);
			archive_read_free(ar);
			return false;
		}

		struct archive_entry* entry;
		while (archive_read_next_header(ar, &entry) == ARCHIVE_OK) {
			/*#define	AES_SET_MBS 1
	#define	AES_SET_UTF8 2
	#define	AES_SET_WCS 4*/
	// 优先级 mbs > utf8 > wcs ,避免压缩包含中文解压乱码
			std::wstring wfile_name;
			const char* entry_name = archive_entry_pathname(entry);
			if (entry_name != nullptr)wfile_name = A2WSTR(entry_name);

			if (wfile_name.empty())
			{
				entry_name = archive_entry_pathname_utf8(entry);
				if (entry_name != nullptr)wfile_name = UTF82WSTR(entry_name);
			}

			if (wfile_name.empty())
			{
				const wchar_t* wentry_name = archive_entry_pathname_w(entry);
				if (wentry_name != nullptr) wfile_name = wentry_name;
			}

			if (wfile_name.empty())
			{
				XLOGW("UnZipPack[%s] archive_entry_sourcepath null", UnZipTrackID.c_str());
				continue;
			}

			std::wstring woutfile = jeflib::FileUtil::JoinPathW(outputDir, wfile_name);
			archive_entry_set_pathname_utf8(entry, W2UTF8CSTR(woutfile));
			nerr = archive_read_extract(ar, entry, ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM); // 保留文件权限和时间戳
			
			const char* szerr = archive_error_string(ar);
			XLOGI("UnZipPack[%s] extract file[%s],extract err:%d,errinfo:%s", UnZipTrackID.c_str(), W2ACSTR(woutfile), nerr, szerr ? szerr:"");
		}
		archive_read_close(ar);
		archive_read_free(ar);
		XLOGI("UnZipPack[%s] finished", UnZipTrackID.c_str());
		return true;
	}
	

unrar

  1. 目前只支持rar格式
#include <iostream>
#include <windows.h>
#include "dll.hpp"  // unrar库头文件

bool ExtractRar(const char* rarPath,const char* outputDir) {
	RAROpenArchiveDataEx arcData = { 0 };
	arcData.ArcName = (char *)rarPath;       // RAR文件路径
	arcData.OpenMode = RAR_OM_EXTRACT; // 解压模式

	// 打开压缩包
	HANDLE hArc = RAROpenArchiveEx(&arcData);
	if (arcData.OpenResult != 0) {
		std::cerr << "打开失败: " << arcData.OpenResult << std::endl;
		return false;
	}

	// 逐文件解压
	RARHeaderDataEx headerData = { 0 };
	int result;
	while ((result = RARReadHeaderEx(hArc, &headerData)) == 0) {
		// 解压当前文件到目标目录
		if (RARProcessFile(hArc, RAR_EXTRACT, (char *)outputDir,nullptr) != 0) {
			RARCloseArchive(hArc);
			return false;
		}
	}

	RARCloseArchive(hArc);
	return (result == ERAR_SUCCESS); // 检查是否解压完成
}

压缩文件

eg:tar.gz格式的压缩包
如果不设置filter则默认为tar

int archiveTar(const std::vector<std::string>& fpaths, const std::string& tarpath)
{
	struct archive* ar = archive_write_new();
	//设置gzip压缩方式,依赖zlib,文件名需要和filter匹配 get:.tat.gz
	archive_write_add_filter_gzip(ar);
	// 设置格式为 tar
	archive_write_set_format_gnutar(ar);
	
	defer(if (ar) archive_write_free(ar); ar = nullptr;);

	int nerr = archive_write_open_filename(ar, tarpath.c_str());
	if (nerr != ARCHIVE_OK) {
		const char* szerr = archive_error_string(ar);
		std::cerr << "文件打开失败:" << szerr <<std::endl;
		archive_read_free(ar);
		return nerr;
	}

	defer(if (ar) archive_write_close(ar););
	for (auto &fpath:fpaths)
	{
		struct _stat64 st;
		if (0 == _stat64(fpath.c_str(), &st))
		{
			auto entry = archive_entry_new();
			defer(if (entry)archive_entry_free(entry); entry = nullptr;);

			archive_entry_set_pathname(entry, fpath.c_str());
			archive_entry_set_size(entry, st.st_size);
			if (st.st_mode & S_IFREG)
				archive_entry_set_filetype(entry, AE_IFREG);
			else if (st.st_mode & S_IFDIR)
				archive_entry_set_filetype(entry, AE_IFDIR);
			else
				continue;

			archive_entry_set_perm(entry, 0644);
			archive_entry_set_mtime(entry, st.st_mtime, 0);

			// 写入头信息
			nerr = archive_write_header(ar, entry);
			if (nerr != ARCHIVE_OK) {
				std::cerr << "文件打开失败!" << std::endl;
				return nerr;
			}
			// 写入文件内容
			FILE* fd = _fsopen(fpath.c_str(), "r+b", _SH_DENYWR);
			defer(if (fd)fclose(fd); fd = nullptr;);

			if (fd)
			{
				int len = 0;
				char szbuf[10240] = "";
				while ((len = fread(szbuf, 1, 10240, fd)) > 0)
				{
					archive_write_data(ar, szbuf, len);
				}
			}
			
		}
	}
	
	return 0;
}

demo:

std::vector<std::string> fpaths;
	fpaths.push_back("d:\\test\\zstd.crs");
	fpaths.push_back("d:\\test\\zstd.h2");
	fpaths.push_back("D:\\test\\中文\\zstd.h");
	fpaths.push_back("D:\\test\\plug\\");
	archiveTar(fpaths, "d:\\test\\zstd.tar.gz");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值