libzip 编译和使用

news2024/11/30 20:34:26

本文参考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;
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2215305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis学习笔记:整数集合

概述 整数集合&#xff08;intset&#xff09;是集合键的底层实现之一&#xff0c;当一个集合只包含整数值元素&#xff0c;并且这个集合的元素数量不多时&#xff0c;Redis就会使用整数集合作为集合键的底层实现。它可以保存类型为int16_t、int32_t或者int64_t的整数值&#…

经典文献阅读之--RGBD GS-ICP SLAM(结合ICP和3D GS构建最快的稠密SLAM)

0. 简介 同时定位与地图构建&#xff08;SLAM&#xff09;的密集表示在机器人技术、虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;应用中扮演了关键角色。在密集表示SLAM的最新进展中&#xff0c;利用神经场景表示和3D高斯表示以实现高保真的空间表…

Redis拒绝连接问题分析与解决方案

目录 前言1. 问题描述2. Redis拒绝连接的常见原因分析2.1 Redis服务未启动2.2 Redis配置中的绑定地址问题2.3 防火墙或安全组问题2.4 Redis连接池耗尽2.5 Redis服务器负载过高2.6 权限配置问题 3. 深度解决方案和优化建议4. 总结 前言 在分布式系统中&#xff0c;Redis作为高性…

【WRF工具】QGis插件GIS4WRF:根据嵌套网格生成namelist.wps文件

【WRF工具】QGis插件GIS4WRF:根据嵌套网格生成namelist.wps文件 准备:WRF嵌套网格QGis根据嵌套网格生成namelist.wps文件检查:根据namelist.wps绘制模拟区域参考GIS4WRF 是一个免费且开源的 QGIS 插件,旨在帮助研究人员和从业者进行高级研究天气研究与预报(WRF)模型的建模…

Java面试题———SpringBoot篇

目录 1、项目中为什么选择SpringBoot 2、SpringBoot的自动装配原理 3、SpringBoot的核心注解是哪个 4、SpringBoot中的starter是干什么的 5、SpringBoot可以有哪些方式加载配置 6、bootstrap.yml和application.yml有何区别 7、SpringBoot读取配置的方式有几种 8、Spring…

基于Springboot+Vue的出租车服务管理系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 包括管…

mysql查看和修改默认配置

1.查看最大连接数 SELECT max_connections; 或者 SHOW VARIABLES LIKE max_connections;2.查看当前连接的客户端 SHOW PROCESSLIST;2.临时设置最大连接数 SET GLOBAL max_connections 500;3.临时设置连接客户端交互超时时间 SET GLOBAL interactive_timeout 1800;4.永久生…

英国放弃了一个领地 却连累.io域名也要消失了

或许&#xff0c;哥几个听说过. io 这个域名吗&#xff1f;常年鼓捣技术的差友应该更清楚&#xff0c;.io 这个域名在圈子里的受欢迎程度。因为 io &#xff0c;或者说 I/O &#xff0c;在计算机领域是 Input/Output &#xff08; 输入 / 输出 &#xff09;的缩写&#xff0c;而…

面试题:Redis(五)

1. 面试题 面试问 记录对集合中的数据进行统计 在移动应用中&#xff0c;需要统计每天的新增用户数和第2天的留存用户数&#xff1b; 在电商网站的商品评论中&#xff0c;需要统计评论列表中的最新评论&#xff1b; 在签到打卡中&#xff0c;需要统计一个月内连续打卡的用户数&…

Java实现八种排序

目录 分类 直接插入排序 希尔排序 选择排序 堆排序 冒泡排序 快速排序 挖坑法 hoare法 双指针法 优化 非递归实现 归并排序 非递归实现 计数排序 分类 这里的排序可以分为两大类&#xff0c; 基于比较的排序非基于比较的排序 其中有七种基于比较的排序&…

.NET 一款读取Excel文件敏感数据的工具

01阅读须知 此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等&#xff08;包括但不限于&#xff09;进行检测或维护参考&#xff0c;未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xf…

【机器学习】智能聊天机器人——基于自然语言处理的智能对话系统

1. 什么是自动化客户服务与智能聊天机器人&#xff1f; 自动化客户服务是一种通过技术手段自动处理客户问题的服务方式&#xff0c;能够在无需人工干预的情况下为客户提供即时、准确的帮助。这种服务通常依托智能系统&#xff0c;通过预设的响应机制或学习历史数据&#xff0c…

数电(编码器、数据分配器、数据选择器)

目录 一、编码器&#xff1a; 1.二进制编码器&#xff1a; 三、优先编码器&#xff08;Priority Encoder&#xff09; 1.二-十进制优先编码器 二、数据分配器和数据选择器(功能正好相反) 1.数据分配器 2.数据选择器 一、编码器&#xff1a; 1.二进制编码器&#xff1a; …

【Linux系统编程】第三十二弹---动态库实战指南:从零构建与高效集成的奥秘

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、动态库 1.1、怎么做动态库 1.2、怎么使用动态库 2、外部库使用 1、动态库 1.1、怎么做动态库 方式一 1、将.c文件编…

创客项目秀|基于XIAO ESP32C3的Night Lamp With Chinese Traditional Pane项目

Fab Academy&#xff0c;源自麻省理工学院的先进教育项目&#xff0c;致力于培养具有全球视野的创新者和制造者。通过密集学习和实践&#xff0c;学生们掌握了从基础到高级的制造技术&#xff0c;学习了如何将创意转化为现实。今天小编给大家带来的是Fab academy学员Dion Tsang…

前端全栈混合之路Deno篇:Deno2.0与Bun对比,谁更胜一筹?或者说谁更适合怎样的项目

在前端全栈开发中&#xff0c;工具的不断演变让开发者们始终在寻找更高效、更现代化的解决方案。继Node.js之后&#xff0c;Deno和Bun 成为了两个比较火热的运行时。Deno2.0的近期的发布让它在性能和兼容性方面大幅提升-尤其是兼容了npm包&#xff08;但我感觉应该不是全部兼容…

如何给低代码平台取名?命名策略与技巧全解析

低代码平台正日益成为企业数字化转型的重要工具。为了确保您的平台能够脱颖而出&#xff0c;吸引到更多的用户和开发者&#xff0c;选择一个恰到好处的名字至关重要。本文将探讨如何为您的低代码平台选择一个既独特又易于记忆的好名字&#xff0c;并详细介绍一系列行之有效的命…

第二百七十九节 JPA教程 - JPA查询IN一对多示例

JPA教程 - JPA查询IN一对多示例 以下JPQL显示如何在一对多映射中使用IN运算符。 executeAndPrintQuery("SELECT DISTINCT p FROM Employee e, IN(e.directs) p");例子 下面的代码来自Department.java。 package cn.w3cschool.common;import java.util.ArrayList; …

中药药材推荐系统

毕业设计还在发愁选题&#xff1f;又想实用又怕复杂&#xff1f;那这篇介绍你一定感兴趣&#xff01; 今天为大家推荐一个基于Django框架开发的中药药材推荐系统&#xff0c;简洁易用&#xff0c;功能丰富&#xff0c;非常适合毕业设计。无论你是技术经验丰富的开发人员&#…

praat语音标注

一、软件下载 praat软件下载链接 下载后双击 二、软件界面