libzip 编译和使用

本文参考libzip开发笔记(一):libzip库介绍、编译和工程模板
libzip解压缩方法分析

libzip依赖zlib,所以编译libzip之前需要先编译zlib。

假设已经编译好zlib
CMake打开Zlib

在这里插入图片描述
指定ZIB_INCLUDE_DIR目录需包含zlib.hzconf.h(在zlib编译目录下)

此时即可生成zip.dllzip.lib

libzip使用

  1. 将头文件,lib,dll拷贝到工程引入即可。
注意事项
  1. zip 文件名编码要求utf-8
  2. 解压文件的时候需要还原文件修改时间
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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值