本文参考libzip开发笔记(一):libzip库介绍、编译和工程模板
libzip解压缩方法分析
libzip依赖zlib,所以编译libzip之前需要先编译zlib。
假设已经编译好zlib
CMake打开Zlib
指定ZIB_INCLUDE_DIR
目录需包含zlib.h
和zconf.h(在zlib编译目录下)
此时即可生成zip.dll
和zip.lib
libzip使用
- 将头文件,lib,dll拷贝到工程引入即可。
注意事项
- zip 文件名编码要求utf-8
- 解压文件的时候需要还原文件修改时间
namespace XZIP
{
bool ZipFile(const std::string& file, zip_t* hzip)
{
if (hzip == nullptr)
{
XLOGW("ZipFile[%I64d] failed,hzip == null,file[%s]", hzip, file.c_str());
return false;
}
//std::ifstream ifile(file, std::ios::binary);
//if (!ifile.is_open())
//{
// XLOGW("CompressFile2Zip[%I64d] failed,file[%s] open failed", hzip, file.c_str());
// return;
//}
//std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(ifile), {});
//第四个参数如果非0,会自动托管申请的资源,直到zip_close之前自动销毁。
//zip_source_t* source = zip_source_buffer(hzip, buffer.data(), buffer.size(), 0);
std::string u8_file = A2UTF8CSTR(file);
if (IsDirectory(file))
{
zip_dir_add(hzip, u8_file.c_str(), ZIP_FL_ENC_UTF_8);
return true;
}
zip_source_t* source = zip_source_file(hzip, u8_file.c_str(), 0, -1);
if (source)
{
//如果add成功则source由zlib自己管理内存并是否
if (zip_file_add(hzip, u8_file.c_str(), source, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8) < 0)
{
XLOGW("ZipFile[%I64d] failed,add file[%s] err:%s", hzip, file.c_str(), zip_strerror(hzip));
zip_source_free(source);
return false;
}
}
else
{
XLOGW("ZipFile[%I64d] failed,create zip source[%s] err:%s", hzip, file.c_str(), zip_strerror(hzip));
return false;
}
XLOGI("ZipFile[%I64d] Ok,file[%s]", hzip, file.c_str());
return true;
}
bool ZipFiles(const std::vector<std::string>& file_paths/*支持目录和文件*/, const std::string& zip_file)
{
int errorCode = 0;
zip_t* hZip = zip_open(A2UTF8CSTR(zip_file), ZIP_CREATE | ZIP_TRUNCATE, &errorCode);
if (hZip)
{
for (auto& it : file_paths)
{
//如果是目录则遍历目录下所有文件
if (IsDirectory(it))
{
//将本身加入压缩项,可能是空文件夹
ZipFile(it, hZip);
std::map<std::string, std::vector<jeflib::FileUtil::FILESTATA>> files;
jeflib::FileUtil::ListDirRecursiveA(it, files);
for (auto& dirItem : files)
{
for (auto& it : dirItem.second)
{
if (it.ctype == 0)
ZipFile(JoinPath(dirItem.first, it.name), hZip);
else if (it.ctype == 1)
ZipFile(JoinPath(dirItem.first, it.name), hZip);
}
}
}
else
ZipFile(it, hZip);
}
errorCode = zip_close(hZip);
if (errorCode != 0)
{
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
XLOGW("ZipFile Failed zip_close zip[%I64d] file[%s],err:%s", hZip, zip_file.c_str(), zip_error_strerror(&zipError));
zip_error_fini(&zipError);
}
}
else
{
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
XLOGW("ZipFile Failed to open zip file[%s],err:%s", zip_file.c_str(), zip_error_strerror(&zipError));
zip_error_fini(&zipError);
}
return errorCode == 0;
}
bool UnZipFile(const std::string& zip_file, bool boverwite/*是否覆盖已经存在的文件*/, std::function<bool(std::string& file)> is_need_unzip)
{
int errorCode = 0;
zip_t* hZip = zip_open(A2UTF8CSTR(zip_file), ZIP_RDONLY, &errorCode);
if (hZip)
{
zip_int64_t num_entries = zip_get_num_entries(hZip, 0);
XLOGI("UnZipFile[%I64d][%s] zip_get_num_entries size:%d", hZip, zip_file.c_str(), num_entries);
if (num_entries != -1)
{
struct zip_stat stat;
for (zip_int64_t i = 0; i < num_entries; ++i)
{
//name全路径
if (zip_stat_index(hZip, i, 0, &stat) != 0)
{
XLOGI("UnZipFile[%I64d][%s] zip_stat_index[%d] failed", hZip, zip_file.c_str(), i);
continue;
}
std::string file_path = UTF82ASTR(stat.name);
if (is_need_unzip && !is_need_unzip(file_path))
{
XLOGI("UnZipFile[%I64d][%s] skip file[%s],no need unzip", hZip, zip_file.c_str(), file_path.c_str());
continue;
}
//如果文件已经存在并且不覆盖则直接跳过
if (!boverwite && _access(file_path.c_str(), 00) == 0)
{
XLOGI("UnZipFile[%I64d][%s] skip file[%s]", hZip, zip_file.c_str(), file_path.c_str());
continue;
}
zip_file_t* zf = zip_fopen_index(hZip, i, 0);
XLOGI("UnZipFile[%I64d][%s] zip_fopen_index index:%d zf:%I64d ", hZip, zip_file.c_str(), file_path.c_str(), i, zf);
if (zf)
{
//创建目标所在目录并创建文件
std::string dir = GetFileDirName(file_path);
CreateDir(dir);
FILE* fp = fopen(file_path.c_str(), "wb");
XLOGI("UnZipFile[%I64d][%s] index[%d] create file[%I64d][%s],errcode:%d", hZip, zip_file.c_str(), i, fp, file_path.c_str(), fp ? 0 : errno);
if (fp)
{
char szbuf[10240] = "";
zip_int64_t itotal_read = 0;
while (itotal_read < stat.size)
{
zip_int64_t iread = zip_fread(zf, szbuf, 10240);
if (iread < 0)
{
break;
}
fwrite(szbuf, 1, iread, fp);
itotal_read += iread;
}
fclose(fp);
if (itotal_read != stat.size)
{
XLOGW("UnZipFile[%I64d][%s] index[%d] file[%s] read failed,read_size[%i64d] file_size[%I64d]", hZip, zip_file.c_str(), i, file_path.c_str(), itotal_read, stat.size);
_unlink(file_path.c_str());
}
//还原文件修改时间
struct _utimbuf ut;
auto ltm = localtime(&stat.mtime);
ut.modtime = mktime(ltm);
ut.actime = 0;
_utime(file_path.c_str(), &ut);
}
zip_fclose(zf);
}
}
return true;
}
errorCode = zip_close(hZip);
if (errorCode != 0)
{
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
XLOGW("UnZipFile[%I64d][%s] Failed zip_close,err:%s", hZip, zip_file.c_str(), zip_error_strerror(&zipError));
zip_error_fini(&zipError);
}
}
else
{
zip_error_t zipError;
zip_error_init_with_code(&zipError, errorCode);
XLOGW("UnZipFile[null][%s] Failed to open zip file,err:%s", zip_file.c_str(), zip_error_strerror(&zipError));
zip_error_fini(&zipError);
}
return false;
}
}