C/C++ Zlib库调用Minzip来封装MyZip压缩类

news2024/11/15 17:51:12

文章目录

  • 1、C/C++ Zlib库调用Minzip来封装MyZip压缩类
      • 1.1、类的功能实现
        • 1.1.1、ZIP压缩函数 Compress
        • 1.1.2、ZIP解压函数 UnCompress
        • 1.1.3、代码如下
        • 1.1.4、如何使用类

1、C/C++ Zlib库调用Minzip来封装MyZip压缩类

Zlib是一个开源的数据压缩库,提供了一种通用的数据压缩和解压缩算法。它最初由 Jean-Loup GaillyMark Adler开发,旨在成为一个高效、轻量级的压缩库,其被广泛应用于许多领域,包括网络通信、文件压缩、数据库系统等。其压缩算法是基于DEFLATE算法,这是一种无损数据压缩算法,通常能够提供相当高的压缩比。

在软件开发中,文件的压缩和解压缩是一项常见的任务,而ZIP是一种被广泛应用的压缩格式。为了方便地处理ZIP压缩和解压缩操作,开发者通常使用各种编程语言和库来实现这些功能。本文将聚焦于一个简化的C++`实现,通过分析代码,我们将深入了解其设计和实现细节。

1.1、类的功能实现

MyZip类旨在提供简单易用的ZIP压缩和解压缩功能。通过成员函数CompressUnCompress,该类使得对目录的ZIP压缩和ZIP文件的解压变得相对容易。

1.1.1、ZIP压缩函数 Compress

Compress函数通过zlib库提供的MINZIP压缩功能,递归地将目录下的文件添加到ZIP文件中。其中,CollectfileInDirtoZip函数负责遍历目录,而AddfiletoZip函数则用于添加文件到ZIP中。这种设计使得代码模块化,易于理解。

1.1.2、ZIP解压函数 UnCompress

UnCompress函数通过zlib库提供的ZIP解压功能,将ZIP文件解压到指定目录。函数中使用了unzip系列函数来遍历ZIP文件中的文件信息,并根据文件类型进行相应的处理。这包括创建目录和写入文件,使得解压后的目录结构与ZIP文件一致。

1.1.3、代码如下

将如上的压缩与解压方法封装成MyZip类,调用zip.Compress()实现压缩目录,调用zip.UnCompress()则实现解压缩目录。这些函数使用了zlib库的ZIP压缩和解压缩功能,并可以在项目中被应用,该类代码如下所示:

#define ZLIB_WINAPI
#include <string>
#include <iostream>
#include <vector>
#include <Shlwapi.h> 
#include <zip.h>
#include <unzip.h>
#include <zlib.h>

using namespace std;

#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "zlibstat.lib")

class MyZip
{
private:
	// 向ZIP文件中添加文件
	bool AddfiletoZip(zipFile zfile, const std::string& fileNameinZip, const std::string& srcfile)
	{
		if (NULL == zfile || fileNameinZip.empty())
		{
			return false;
		}

		int nErr = 0;
		zip_fileinfo zinfo = { 0 };
		tm_zip tmz = { 0 };
		zinfo.tmz_date = tmz;
		zinfo.dosDate = 0;
		zinfo.internal_fa = 0;
		zinfo.external_fa = 0;

		// 构建新文件名
		char sznewfileName[MAX_PATH] = { 0 };
		memset(sznewfileName, 0x00, sizeof(sznewfileName));
		strcat_s(sznewfileName, fileNameinZip.c_str());
		if (srcfile.empty())
		{
			strcat_s(sznewfileName, "\\");
		}

		// 在ZIP中打开新文件
		nErr = zipOpenNewFileInZip(zfile, sznewfileName, &zinfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
		if (nErr != ZIP_OK)
		{
			return false;
		}

		// 如果有源文件,读取并写入ZIP文件
		if (!srcfile.empty())
		{
			FILE* srcfp = _fsopen(srcfile.c_str(), "rb", _SH_DENYNO);
			if (NULL == srcfp)
			{
				return false;
			}

			int numBytes = 0;
			char* pBuf = new char[1024 * 100];
			if (NULL == pBuf)
			{
				return false;
			}

			// 逐块读取源文件并写入ZIP
			while (!feof(srcfp))
			{
				memset(pBuf, 0x00, sizeof(pBuf));
				numBytes = fread(pBuf, 1, sizeof(pBuf), srcfp);
				nErr = zipWriteInFileInZip(zfile, pBuf, numBytes);
				if (ferror(srcfp))
				{
					break;
				}
			}

			delete[] pBuf;
			fclose(srcfp);
		}

		// 关闭ZIP文件中的当前文件
		zipCloseFileInZip(zfile);

		return true;
	}

	// 递归地将目录下的文件添加到ZIP
	bool CollectfileInDirtoZip(zipFile zfile, const std::string& filepath, const std::string& parentdirName)
	{
		if (NULL == zfile || filepath.empty())
		{
			return false;
		}

		bool bFile = false;
		std::string relativepath = "";
		WIN32_FIND_DATAA findFileData;

		char szpath[MAX_PATH] = { 0 };
		if (::PathIsDirectoryA(filepath.c_str()))
		{
			strcpy_s(szpath, sizeof(szpath) / sizeof(szpath[0]), filepath.c_str());
			int len = strlen(szpath) + strlen("\\*.*") + 1;
			strcat_s(szpath, len, "\\*.*");
		}
		else
		{
			bFile = true;
			strcpy_s(szpath, sizeof(szpath) / sizeof(szpath[0]), filepath.c_str());
		}

		HANDLE hFile = ::FindFirstFileA(szpath, &findFileData);
		if (NULL == hFile)
		{
			return false;
		}

		do
		{
			// 构建相对路径
			if (parentdirName.empty())
				relativepath = findFileData.cFileName;
			else
				relativepath = parentdirName + "\\" + findFileData.cFileName;

			// 如果是目录,递归处理子目录
			if (findFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
			{
				if (strcmp(findFileData.cFileName, ".") != 0 && strcmp(findFileData.cFileName, "..") != 0)
				{
					AddfiletoZip(zfile, relativepath, "");

					char szTemp[MAX_PATH] = { 0 };
					strcpy_s(szTemp, filepath.c_str());
					strcat_s(szTemp, "\\");
					strcat_s(szTemp, findFileData.cFileName);
					CollectfileInDirtoZip(zfile, szTemp, relativepath);
				}
				continue;
			}

			char szTemp[MAX_PATH] = { 0 };
			if (bFile)
			{
				strcpy_s(szTemp, filepath.c_str());
			}
			else
			{
				strcpy_s(szTemp, filepath.c_str());
				strcat_s(szTemp, "\\");
				strcat_s(szTemp, findFileData.cFileName);
			}

			// 将文件添加到ZIP
			AddfiletoZip(zfile, relativepath, szTemp);

		} while (::FindNextFileA(hFile, &findFileData));

		FindClose(hFile);

		return true;
	}

	// 替换字符串中的所有指定子串
	std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value)
	{
		while (true)
		{
			std::string::size_type pos(0);
			if ((pos = str.find(old_value)) != std::string::npos)
				str.replace(pos, old_value.length(), new_value);
			else
				break;
		}
		return str;
	}

	// 创建多级目录
	BOOL CreatedMultipleDirectory(const std::string& direct)
	{
		std::string Directoryname = direct;
		if (Directoryname[Directoryname.length() - 1] != '\\')
		{
			Directoryname.append(1, '\\');
		}

		std::vector< std::string> vpath;
		std::string strtemp;
		BOOL  bSuccess = FALSE;

		// 遍历目录字符串,逐级创建目录
		for (int i = 0; i < Directoryname.length(); i++)
		{
			if (Directoryname[i] != '\\')
			{
				strtemp.append(1, Directoryname[i]);
			}
			else
			{
				vpath.push_back(strtemp);
				strtemp.append(1, '\\');
			}
		}

		std::vector< std::string>::iterator vIter = vpath.begin();
		for (; vIter != vpath.end(); vIter++)
		{
			bSuccess = CreateDirectoryA(vIter->c_str(), NULL) ? TRUE : FALSE;
		}

		return bSuccess;
	}

public:
	// 压缩目录
	bool Compress(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName)
	{
		bool bRet = false;
		zipFile zFile = NULL;

		// 根据ZIP文件是否存在选择打开方式
		if (!::PathFileExistsA(zipfileName.c_str()))
		{
			zFile = zipOpen(zipfileName.c_str(), APPEND_STATUS_CREATE);
		}
		else
		{
			zFile = zipOpen(zipfileName.c_str(), APPEND_STATUS_ADDINZIP);
		}

		if (NULL == zFile)
		{
			return bRet;
		}

		// 将目录下的文件添加到ZIP
		if (CollectfileInDirtoZip(zFile, dirpathName, parentdirName))
		{
			bRet = true;
		}

		zipClose(zFile, NULL);

		return bRet;
	}

	// 解压目录
	bool UnCompress(const std::string& strFilePath, const std::string& strTempPath)
	{
		int nReturnValue;
		string tempFilePath;
		string srcFilePath(strFilePath);
		string destFilePath;

		// 打开ZIP文件
		unzFile unzfile = unzOpen(srcFilePath.c_str());
		if (unzfile == NULL)
		{
			return false;
		}

		unz_global_info* pGlobalInfo = new unz_global_info;
		nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo);
		if (nReturnValue != UNZ_OK)
		{
			return false;
		}

		unz_file_info* pFileInfo = new unz_file_info;
		char szZipFName[MAX_PATH] = { 0 };
		char szExtraName[MAX_PATH] = { 0 };
		char szCommName[MAX_PATH] = { 0 };

		for (int i = 0; i < pGlobalInfo->number_entry; i++)
		{
			nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, szExtraName, MAX_PATH, szCommName, MAX_PATH);
			if (nReturnValue != UNZ_OK)
				return false;

			string strZipFName = szZipFName;

			// 如果是目录,创建相应目录
			if (pFileInfo->external_fa == FILE_ATTRIBUTE_DIRECTORY || (strZipFName.rfind('/') == strZipFName.length() - 1))
			{
				destFilePath = strTempPath + "//" + szZipFName;
				CreateDirectoryA(destFilePath.c_str(), NULL);
			}
			else
			{
				string strFullFilePath;
				tempFilePath = strTempPath + "/" + szZipFName;
				strFullFilePath = tempFilePath;

				int nPos = tempFilePath.rfind("/");
				int nPosRev = tempFilePath.rfind("\\");
				if (nPosRev == string::npos && nPos == string::npos)
					continue;

				size_t nSplitPos = nPos > nPosRev ? nPos : nPosRev;
				destFilePath = tempFilePath.substr(0, nSplitPos + 1);

				// 创建多级目录
				if (!PathIsDirectoryA(destFilePath.c_str()))
				{
					destFilePath = replace_all(destFilePath, "/", "\\");
					int bRet = CreatedMultipleDirectory(destFilePath);
				}

				strFullFilePath = replace_all(strFullFilePath, "/", "\\");

				// 创建文件并写入数据
				HANDLE hFile = CreateFileA(strFullFilePath.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
				if (hFile == INVALID_HANDLE_VALUE)
				{
					return false;
				}

				nReturnValue = unzOpenCurrentFile(unzfile);
				if (nReturnValue != UNZ_OK)
				{
					CloseHandle(hFile);
					return false;
				}

				uLong BUFFER_SIZE = pFileInfo->uncompressed_size;
				void* szReadBuffer = NULL;
				szReadBuffer = (char*)malloc(BUFFER_SIZE);
				if (NULL == szReadBuffer)
				{
					break;
				}

				// 逐块读取ZIP文件并写入目标文件
				while (TRUE)
				{
					memset(szReadBuffer, 0, BUFFER_SIZE);
					int nReadFileSize = 0;

					nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE);

					if (nReadFileSize < 0)
					{
						unzCloseCurrentFile(unzfile);
						CloseHandle(hFile);
						return false;
					}
					else if (nReadFileSize == 0)
					{
						unzCloseCurrentFile(unzfile);
						CloseHandle(hFile);
						break;
					}
					else
					{
						DWORD dWrite = 0;
						BOOL bWriteSuccessed = WriteFile(hFile, szReadBuffer, BUFFER_SIZE, &dWrite, NULL);
						if (!bWriteSuccessed)
						{
							unzCloseCurrentFile(unzfile);
							CloseHandle(hFile);
							return false;
						}
					}
				}

				free(szReadBuffer);
			}
			unzGoToNextFile(unzfile);
		}

		delete pFileInfo;
		delete pGlobalInfo;

		if (unzfile)
		{
			unzClose(unzfile);
		}

		return true;
	}
};
1.1.4、如何使用类

压缩文件时可以通过调用zip.Compress()函数实现,该函数接受3个参数,第一个参数是需要压缩的目录名,第二个参数是压缩后保存的文件名,第三个参数则是压缩后主目录的名字,我们以压缩D:\\csdn目录下的所有文件为例,代码如下所示:

#include "MyZip.h"

int main(int argc, char* argv[])
{
	MyZip zip;

	// 压缩目录
	std::string compress_src = "F:\\vs2013_code\\ConsoleApplication2\\Debug\\1.txt";                               // 压缩整个目录或者目录下某个文件
	std::string compress_dst = "F:\\vs2013_code\\ConsoleApplication2\\Debug\\test3.zip";                           // 压缩后

	bool compress_flag = zip.Compress(compress_src, compress_dst, "lyshark");
	std::cout << "压缩状态: " << compress_flag << std::endl;

	system("pause");
	return 0;
}

压缩后可以看到对应的压缩包内容,如下所示:

在这里插入图片描述

解压缩与压缩类似,通过调用zip.UnCompress实现,该方法需要传入两个参数,被压缩的文件名和解压到的目录名,如果目录不存在则会创建并解压。

int main(int argc, char* argv[])
{
	MyZip zip;

	// 解压缩目录
	std::string uncompress_src = "D:\\test.zip";                      // 被解压文件
	std::string uncompress_dst = "D:\\dst";                           // 解压到

	bool compress_flag = zip.UnCompress(uncompress_src, uncompress_dst);
	std::cout << "解压缩状态: " << compress_flag << std::endl;

	system("pause");
	return 0;
}

输出效果如下所示:
在这里插入图片描述

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

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

相关文章

JVM调优,调整JVM参数

JDK8之后把-XX:PermSize和-XX:MaxPermGen移除了&#xff0c;取而代之的是XX:MetaspaceSize128m &#xff08;元空间默认大小&#xff09; -XX:MaxMetaspaceSize128m &#xff08;元空间最大大小&#xff09; JDK 8开始把类的元数据放到本地化的堆内存(native heap)中&#xff0…

[VNCTF2024]-PWN:preinit解析(逆向花指令,绕过strcmp,函数修改,机器码)

查看保护&#xff1a; 查看ida&#xff1a; 这边其实看反汇编没啥大作用&#xff0c;需要自己动调。 但是前面的绕过strcmp还是要看一下的。 解题&#xff1a; 这里是用linux自带的产生随机数的文件urandom来产生一个随机密码&#xff0c;然后让我们输入密码&#xff0c;用st…

就业班 2401--3.1 Linux Day9--文件查找和压缩

一、文件查找与打包压缩 grep: 文件内容过滤 [rootqfedu.com ~]# grep root /etc/passwd #从/etc/passwd文件中过滤root字段 grep ^root root$ root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin 查找命令 [rootqfedu.com ~]# which ls ali…

Linux系统中安装redis+redis后台启动+常见相关配置

1、下载Redis Redis官网&#xff1a;https://redis.io/ 历史版本&#xff1a; http://download.redis.io/releases 2、连接Linux&#xff08;或者VMwear&#xff09; 我们安装的是linux版本的redis 打开xftp我们需要先将我们的Redis上传到服务器上 解压到这里 解压的指令 …

Python错题集-4:NameError:(变量名错误)

1问题描述 Traceback (most recent call last): File "D:\pycharm\projects\1-可视化学习\8.3更改小提琴图的中位数、均值、颜色等.py", line 8, in <module> violin_parts plt.violinplot(data, showmediansTrue, showmeansTrue) …

071:vue+cesium 实现下雨效果

第071个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中实现下雨效果,这里使用着色器来实现实例特效。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共120行)着色代码实现心得:专栏目标示例效果

物体检测-系列教程19:YOLOV5 源码解析9 (Focus模块、Model类构造函数)

&#x1f60e;&#x1f60e;&#x1f60e;物体检测-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 点我下载源码 13、Focus模块 13.1 基本流程 原始输入图像的格式为&#xff1a;tensor: float32[1,3,64…

msvcr120.dll丢失的解决办法,分享解决文件丢失的问题

msvcr120.dll文件丢失有这三种方法可以解决&#xff0c;学会这三种方法的任何一种&#xff0c;以后再出现dll文件丢失的情况都能很好地解决&#xff0c;第一种方法最为简单。先给大家说说msvcr120.dll文件为什么会丢失&#xff1f;丢失的原因是什么&#xff1f; 一.msvcr120.d…

LabVIEW眼结膜微血管采集管理系统

LabVIEW眼结膜微血管采集管理系统 开发一套基于LabVIEW的全自动眼结膜微血管采集管理系统&#xff0c;以提高眼结膜微血管临床研究的效率。系统集成了自动化图像采集、图像质量优化和规范化数据管理等功能&#xff0c;有效缩短了图像采集时间&#xff0c;提高了图像质量&#…

【LLM RAG】GritLM:统一嵌入和生成的大语言模型浅谈

前言 目前&#xff0c;所有基于文本的语言问题都可以归结为生成问题&#xff0c;并通过单一的LLM来处理。然而&#xff0c;使用嵌入的任务&#xff08;如聚类或检索&#xff09;在这种视角下往往被忽视了。文本嵌入在许多关键的实际应用中扮演着重要角色。如RAG&#xff0c;在…

NGINX 高频面试题及实践总结

NGINX 是一个高性能的开源 Web 服务器和反向代理服务器&#xff0c;被广泛应用于互联网架构中。在面试中&#xff0c;对 NGINX 的相关知识可能会成为考察的重点。下面我们整理了一些常见的 NGINX 面试题及答案&#xff0c;希望对大家在面试前的准备有所帮助。 ## 1. 什么是 NG…

通过跳板机拷贝远程服务器文件

## 背景 在日常开发或者运维中&#xff0c;经常会遇到开发环境与线上环境网络隔离&#xff0c;需要通过跳板机连接的场景&#xff0c;如果需要将目标机器上的定位信息搬迁到开发机做进一步排查时&#xff0c;经常取文件比较费劲&#xff0c;一般操作是将目标文件拷贝到跳板机&…

SpringBoot项目连接Redis报错:Connection refused: no further information

今天在使用SpringBoot连接Redis时发生了报错 明明Jedis能够连接成功为什么StringRedisTemplate就不行? 然后在网上找了一下说是关闭防火墙或者修改配置文件但是都不管用 最后发现是Redis在SpringBoot3之后yml的配置方式发生了改变 相较于之前多了一个前缀, 由于我刚开始没有…

kotlin开发框架,50家大厂面试万字精华总结

与其它行业一样&#xff0c;凡是有高级和普通&#xff0c;虽然都是敲代码但也有大牛和普通之分&#xff0c;大牛程序员&#xff0c;一个人比一个团队做项目都做得快&#xff0c;**最为出名的当属十几年前求伯君在做wps时&#xff0c;一个人完成了微软二十人团队没有完成的项目需…

嵌入式中回调函数的实现方法

一、什么是回调函数 1.1、回调函数的定义和基本概念 回调函数是一种特殊的函数&#xff0c;它作为参数传递给另一个函数&#xff0c;并在被调用函数执行完毕后被调用。回调函数通常用于事件处理、异步编程和处理各种操作系统和框架的API。 基本概念&#xff1a; 回调&#xf…

【PyTorch】成功解决AttributeError: ‘Tuple‘ object has no attribute ‘cuda‘

【PyTorch】成功解决AttributeError: ‘Tuple‘ object has no attribute ‘cuda‘ &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&…

【教程】移动互联网时代的APP上架流程和要点

目录 摘要 引言 正文 一、应用商店注册 二、准备APP材料 三、打包上传App 摘要 本文将介绍移动应用程序上架的基本流程和要点&#xff0c;包括应用商店注册、APP材料准备、打包上传App、APP审核以及发布APP的详细步骤。此外&#xff0c;还会提到利用appuploder工具简化i…

强大而灵活的python装饰器

装饰器&#xff08;Decorators&#xff09; 一、概述 在Python中&#xff0c;装饰器是一种特殊类型的函数&#xff0c;它允许我们修改或增强其他函数的功能&#xff0c;而无需修改其源代码。装饰器在函数定义之后立即调用&#xff0c;并以函数对象作为参数。装饰器返回一个新…

【Qt】Sqlite数据库加密

1. 加密方式 对数据库文件加密。既不会暴露表结构&#xff0c;也不会暴露数据细节。 2. 加密工具&#xff08;QtCipherSqlitePlugin&#xff09; 用于密码 SQLite 的 Qt 插件&#xff0c;它基于 SQLite 源和 wxWidget 中的 wxSQLite3插件github地址&#xff1a;https://gith…

Vue ElementUI 修改消息提示框样式—messageBox 的大小

在窄屏模式下&#xff08;移动端或pda&#xff09;&#xff0c;提示框的宽度太宽&#xff0c;会出现显示不完全的问题。 应当如何修改 ElementUI 的样式呢&#xff1f; open() {this.$confirm(window.vm.$i18n.t("tips.conLogOut"),window.vm.$i18n.t("tips.tip…