C/C++ Zlib库封装MyZip压缩类

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

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

类的功能实现

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

ZIP压缩函数 Compress

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

ZIP解压函数 UnCompress

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

将如上的压缩与解压方法封装成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 nyAddfiletoZip(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;}// 逐块读取源文件并写入ZIPwhile (!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;}// 递归地将目录下的文件添加到ZIPbool nyCollectfileInDirtoZip(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;elserelativepath = parentdirName + "\\" + findFileData.cFileName;// 如果是目录,递归处理子目录if (findFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY){if (strcmp(findFileData.cFileName, ".") != 0 && strcmp(findFileData.cFileName, "..") != 0){nyAddfiletoZip(zfile, relativepath, "");char szTemp[MAX_PATH] = { 0 };strcpy_s(szTemp, filepath.c_str());strcat_s(szTemp, "\\");strcat_s(szTemp, findFileData.cFileName);nyCollectfileInDirtoZip(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);}// 将文件添加到ZIPnyAddfiletoZip(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);elsebreak;}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;}// 将目录下的文件添加到ZIPif (nyCollectfileInDirtoZip(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;}
};

如何使用类

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

int main(int argc, char* argv[])
{MyZip zip;// 压缩目录std::string compress_src = "D:\\csdn";                               // 压缩目录std::string compress_dst = "D:\\test.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.hqwc.cn/news/233379.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搜维尔科技:Varjo XR-4 系列-专为极致沉浸感而打造!

Varjo 的新一代头显将世界上最先进的混合现实技术与顶尖的图形处理能力连接起来&#xff0c;满足最高级别的视觉保真度和沉浸感至关重要的工业用例。 光学设计的根本性突破 体验全新的沉浸感。大幅扩展的视野&#xff0c;跨越 120 x 105 度&#xff0c;打破了受人尊敬的“全双眼…

最新消息:滴滴 P0 事故原因,原因出来了

最新消息滴滴P0故障原因&#xff0c;是由于k8s集群升级导致的&#xff0c;后面又进行版本回退&#xff0c;由于现在大型互联网公司基本都是基于K8s进行部署的&#xff0c;如果K8s集群一出问题&#xff0c;上面运行的业务Pod和运维系统全部都得宕机&#xff0c;导致没法回滚。 …

8个最流行的Revit插件【2023-2024】

NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 Revit 已取代 AutoCAD 成为全球行业标准软件。 随着设计复杂性的增加&#xff0c;近年来插件变得更加必要。 热…

极智芯 | 解读国产AI算力 登临产品矩阵

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文分享一下 解读国产AI算力 登临产品矩阵。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码和资源下载,链接:https://t.zsxq.com/0aiNxERDq 登临属于 GPGPU 阵营,同属于…

「Qt Widget中文示例指南」如何创建一个计算器?(二)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文将展示如何使用…

linux系统下的nginx服务安装

一. 环境 在安装nginx前&#xff0c;需要提前配置的环境包括 pcre&#xff1a;rewrite正则相关pcre:URL重写软件&#xff0c;实现伪静态\URL跳转等、SEO优化。 openssl&#xff1a;https加密访问用它 zlib&#xff1a;提供数据压缩用1.安装pcre 1.1 检查版本 执行&#xff…

诺亚控股资产管理规模突破1500亿元,财富管理客户数持续增长

近日&#xff0c;诺亚控股发布了2023年第三季度的财务报告&#xff0c;显示公司在该季度取得了稳健的业绩。据报告&#xff0c;诺亚控股在第三季度的净收入达到了7.50亿元人民币&#xff0c;同比增长了9.6%。这一增长主要得益于诺亚控股在财富管理业务方面的强劲表现以及资产管…

SpringBoot application.yml配置文件写法

1&#xff0c;基本介绍 &#xff08;1&#xff09;YAML 是 JSON 的超集&#xff0c;简洁而强大&#xff0c;是一种专门用来书写配置文件的语言&#xff0c;可以替代 application.properties。 &#xff08;2&#xff09;在创建一个 SpringBoot 项目时&#xff0c;引入的 spri…

行业唯一!法大大上榜2023德勤深圳明日之星

11月28日&#xff0c;德勤中国在深圳举办2023德勤深圳高科技高成长20强及明日之星&#xff08;以下简称“深圳明日之星”&#xff09;颁奖盛典。法大大作为高速成长、持续创新的卓越企业荣登深圳明日之星榜单。值得一提的是&#xff0c;法大大是唯一一家获奖的电子签企业&#…

网络和Linux网络_7(传输层)UDP和TCP协议(端口号+确认应答+超时重传+三次握手四次挥手)

目录 1. 重看端口号 1.1 端口号的概念 1.2 端口号的划分 2. 重看UDP协议 2.1 UDP协议格式 2.2 UDP的特点 3. 重看TCP协议 3.1 TCP协议格式 3.2 TCP的解包分用 3.3 TCP的可靠性及机制 3.3.1 确认应答ACK机制 3.3.2 超时重传机制 3.3.3 连接管理机制&#xff08;三次…

Android : GPS定位 获取当前位置—简单应用

示例图&#xff1a; MainActivity.java package com.example.mygpsapp;import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat;import android.Manif…

ROM和RAM概念

一、存储器特性 1&#xff09;易失性&#xff1a;掉电数据会丢失&#xff0c;通常指RAM&#xff1b; RAM分为SRAM、DRAM SRAM&#xff1a;静态RAM&#xff0c;只要上电数据就不会丢失&#xff1b; DRAM&#xff1a;动态RAM&#xff0c;需要每隔一段事件刷新数据&#xff0c;否…