libarchive
Windows下编译 libarchive
- CMake 直接使用默认值 Configure->Generate (默认支持
rar
,不支持zip)
- 根据自己实际需求安装对应的依赖库,eg:BZIP2
- CMake 会出现waring,可以直接忽略
- 整体编译会运行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
- 如果存在中文需使用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
- 目前只支持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");