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

文章目录

  • 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;}// 逐块读取源文件并写入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 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;elserelativepath = 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);}// 将文件添加到ZIPAddfiletoZip(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 (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://xiahunao.cn/news/2822103.html

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

相关文章

Mybatis | Mybatis的核心配置

目录: Mybatis的核心配置 :一、MyBatis的 “核心对象”1.1 SqlSessionFactory1.2 SqlSession :SqlSession对象中的操作数据库的方法 :\<T> T selectOne ( String statement )\<T> T selectOne( String statement , Object parameter )\<E> List\<E> se…

android程序员面试笔试宝典,Android开发社招面试总结

部分面试常问的面试专题 一、Java篇 1.多线程并发&#xff1b; sleep 和 wait 区别join 的用法线程同步&#xff1a;synchronized 关键字等线程通信线程池手写死锁 2.Java 中的引用方式&#xff0c;及各自的使用场景 3.HashMap 的源码 4.GC(垃圾回收)是什么&#xff1f;如何…

日本极致产品力|如何利用招牌业务,打造占据63%市场份额的咖喱品牌

招牌产品是品牌的代表性产品&#xff0c;行业中领先品牌的招牌产品往往可以代表整个品类。在内线产品竞争中&#xff0c;通过在顾客心智中确立一个强势招牌产品形象可以提高品牌势能。好侍能够成为日本调味品头部品牌&#xff0c;通过香辛料招牌业务获取增长是其成功的关键。 从…

分享6个解决msvcp110.dll丢失的方法,全面解析msvcp110.dll文件

msvcp110.dll 是一个动态链接库 (DLL) 文件&#xff0c;属于 Microsoft Visual C 库的一部分&#xff0c;具体来说是 Microsoft Visual C 2012 版本的运行时组件。这个 DLL 文件包含了在 Windows 环境下运行用 C 编写的程序所必需的一些函数和资源。当一个应用程序是使用 Visua…

基于Python3的数据结构与算法 - 07 归并排序

一、归并 引入 假设现在的列表分两段有序&#xff0c;如何将其合并成为一个有序列表。 这种操作成为一次归并。 归并的思路 分别对两个列表进行遍历&#xff0c;比较两个列表中的最小值&#xff0c;将更小的取出来。取出后一次进行上操作&#xff0c;直到其中一个列表中的元…

1分钟学会Python字符串前后缀与编解码

1.前缀和后缀 前缀和后缀指的是&#xff1a;字符串是否以指定字符开头和结尾 2.startswith() 判断字符串是否以指定字符开头&#xff0c;若是返回True&#xff0c;若不是返回False str1 "HelloPython"print(str1.startswith("Hello")) # Trueprint…

【转载】深度学习笔记——详解损失函数

原文链接: https://blog.csdn.net/weixin_53765658/article/details/136360033 CSDN账号: Purepisces github账号: purepisces 希望大家可以Star Machine Learning Blog https://github.com/purepisces/Wenqing-Machine_Learning_Blog 损失函数 根据您使用的神经网络类型和数…

力扣SQL50 进店却未进行过交易的顾客 查询

Problem: 1581. 进店却未进行过交易的顾客 文章目录 思路Code 思路 &#x1f468;‍&#x1f3eb; 山山山林老木 左连接查询筛选 transation_id 为 null 的值group by customer_id Code select v.customer_id ,count(customer_id) count_no_trans from Visits v left jo…

java找工作之JavaWeb(一)

JavaWeb 一个web应用有多部份组成&#xff08;静态web&#xff0c;动态web&#xff09; html&#xff0c;css&#xff0c;jsjsp&#xff0c;servletjava程序jar包配置文件(Properties) web应用程序编写完毕后&#xff0c;若想提供给外界访问&#xff0c;需要一个服务器来统一…

3694-51-7,3,5-Dinitro-1,2-phenylenediamine,合成其他化合物的重要中间体

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;3694-51-7&#xff0c;3,5-Dinitro-1,2-phenylenediamine&#xff0c;3,5-二硝基-1,2-苯二胺;3,5-二硝基苯-1,2-二胺 一、基本信息 【产品简介】&#xff1a;3,5-Dinitro-1,2-phenylenediamine, with the molecular…

一台工控机的能量

使用Docker搭建EPICS的IOC记录 Zstack EPICS Archiver在小课题组的使用经验 以前电子枪调试&#xff0c;用一台工控机跑起束测后台&#xff0c;这次新光源用的电子枪加工回来又是测试&#xff0c;又是用一台工控机做起重复的事&#xff0c;不过生命在于折腾&#xff0c;重复的…

openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划

文章目录 openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划 openGauss学习笔记-232 openGauss性能调优-系统调优-资源负载管理-资源管理准备-资源规划 完成资源负载管理功能配置前&#xff0c;需要先根据业务模型完成租户资源的规划。业…

【白嫖8k买的机构vip教程】Appium自动化(3):Appium-Desktop界面介绍

Appium-Desktop主界面包含三个菜单Simple、Advanced、Presets Simple界面&#xff1a; Host设置Appium server的ip地址&#xff0c;本地调试可以将ip地址修改为127.0.0.1&#xff1b;Port设置端口号&#xff0c;默认是4723不用修改Start Server 启动 Appium serverEdit Confi…

[SUCTF 2019]EasyWeb --不会编程的崽

个人认为&#xff0c;这题还算有些东西。先来看源码 <?php function get_the_flag(){// webadmin will remove your upload file every 20 min!!!! $userdir "upload/tmp_".md5($_SERVER[REMOTE_ADDR]);if(!file_exists($userdir)){mkdir($userdir);}if(!empty…

【力扣白嫖日记】550.游戏玩法分析IV

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 550.游戏玩法分析IV 表&#xff1a;Activity 列名类型player_idintdevice_idintevent_datedategames_played…

leetcode--接雨水(双指针法,动态规划,单调栈)

目录 方法一&#xff1a;双指针法 方法二&#xff1a;动态规划 方法三&#xff1a;单调栈 42. 接雨水 - 力扣&#xff08;LeetCode&#xff09; 黑色的是柱子&#xff0c;蓝色的是雨水&#xff0c;我们先来观察一下雨水的分布情况: 雨水落在凹槽之间&#xff0c;在一个凹槽的…

第三百七十五回

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"分享三个使用TextField的细节"相关的内容&#xff0c;本章回中将介绍如何让Text组件中的文字自动换行.闲话休提&#xff0c;让我们一起Talk Flutter吧。 …

《C++进阶--10.多态》

目录 10. 多态 10.1 多态的基本概念 10.2 多态案例一-计算器类 10.3 纯虚函数和抽象类 10.4 多态案例二-制作饮品 10.5 虚析构和纯虚析构 10.6 多态案例三-电脑组装 10. 多态 10.1 多态的基本概念 多态是C面向对象三大特性之一 多态分为两类 静态多态: 函数重载 和 运算…

HTML---Ajax

文章目录 目录 文章目录 前言 一.Ajax概述 二.原生创建Ajax 三,使用Jquery处理Ajax 总结 一.Ajax概述 AJAX&#xff08;Asynchronous Javascript And XML&#xff09;是一种创建交互式网页应用的网页开发技术。它使用Javascript语言与服务器进行异步交互&#xff0c;可以传…

matplotlib.animation 3d姿态动画

目录 演示效果&#xff1a; 演示代码&#xff1a; 保存为gif 演示效果&#xff1a; 演示代码&#xff1a; import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotlib.animation import FuncAnimation# 定义人体关键点…