C/C++ Zlib库封装MyZip压缩类
Zlib是一个开源的数据压缩库,提供了一种通用的数据压缩和解压缩算法。它最初由Jean-Loup Gailly和Mark Adler开发,旨在成为一个高效、轻量级的压缩库,其被广泛应用于许多领域,包括网络通信、文件压缩、数据库系统等。其压缩算法是基于DEFLATE算法,这是一种无损数据压缩算法,通常能够提供相当高的压缩比。
在软件开发中,文件的压缩和解压缩是一项常见的任务,而ZIP是一种被广泛应用的压缩格式。为了方便地处理ZIP压缩和解压缩操作,开发者通常使用各种编程语言和库来实现这些功能。本文将聚焦于一个简化的C++实现,通过分析代码,我们将深入了解其设计和实现细节。
类的功能实现
MyZip类旨在提供简单易用的ZIP压缩和解压缩功能。通过成员函数Compress和UnCompress,该类使得对目录的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;
}
// 逐块读取源文件并写入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 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;
else
relativepath = 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);
}
// 将文件添加到ZIP
nyAddfiletoZip(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 (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;
}
输出效果如下所示;

C/C++ Zlib库封装MyZip压缩类的更多相关文章
- 使用libzplay库封装一个音频类
装载请说明原地址,谢谢~~ 前两天我已经封装好一个duilib中使用的webkit内核的浏览器控件和一个基于vlc的用于播放视频的视频控件,这两个控件可以分别用在放酷狗播放器的乐库功能和MV ...
- [Zlib]_[0基础]_[使用zlib库压缩文件]
场景: 1. WIndows上没找到系统提供的win32 api来生成zip压缩文件, 有知道的大牛麻烦留个言. 2. zlib比較经常使用,编译也方便,使用它来做压缩吧. MacOSX平台默认支持z ...
- [Zlib]_[初级]_[使用zlib库压缩和解压STL string]
场景 1.一般在使用文本json传输数据, 数据量特别大时,传输的过程就特别耗时, 因为带宽或者socket的缓存是有限制的, 数据量越大, 传输时间就越长. 网站一般使用gzip来压缩成二进制. 说 ...
- Labview 错误1400-打包库封装类时将对类重命名导致
现象 今天遇到了一个神奇的BUG,主程序调用了一个包含类的打包库,打包库中将字符串还原为类句柄时报错. 调用程序结构如下:. 主程序中将类句柄转化为XML字符串程序如下: 打包库内将字符串还原为句柄程 ...
- python使用zlib库压缩图片,使用ffmpeg压缩视频
python压缩图片.视频 图片压缩使用zlib库 视频压缩使用工具ffmpeg # ffmpeg -i 1.mp4 -r 10 -pix_fmt yuv420p -vcodec libx264 -p ...
- 【VC++技术杂谈008】使用zlib解压zip压缩文件
最近因为项目的需要,要对zip压缩文件进行批量解压.在网上查阅了相关的资料后,最终使用zlib开源库实现了该功能.本文将对zlib开源库进行简单介绍,并给出一个使用zlib开源库对zip压缩文件进行解 ...
- vs2013载入zlib库,即include "zlib.h"
转自wo13142yanyouxin原文vs2013载入zlib库,即include "zlib.h" 在程序中,我们经常要用到压缩,解压函数.以压缩函数compress为例进行说 ...
- 利用zlib库进行zip解压
1:到zlib官网上下载zlib,本文下载的是1.2.8的版本. 2:进行./configure,然后make. 3:进入zlib库中的contrib/minizip/路径下make,生成的miniz ...
- 【转】 C++使用zlib库(-)
来自: http://blog.chinaunix.net/uid-24607609-id-2118143.html 今天看到一个gzopen函数,搜了一下他的系列函数,及相关用法 C++使 ...
- ZLIB 库
zlib 编辑 zlib是提供数据压缩用的函式库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表.zlib使用DEFLATE算法,最初是为libp ...
随机推荐
- 【工具】-Reverse-DIE(Detect-It-Easy)
关于 Detect It Easy,或缩写为"DIE"是一个用于确定文件类型的程序.Detect It Easy 是一个多功能的 PE 检测工具,基于 QT 平台编写,主要用于 P ...
- python实现创建一个银行类,这个类实现了两个方法,第一个方法可以将用户信息写入到文件中,第二个方法可以读取文件中的用户信息出来
class bank: def user_info(self): a=input('请输入用户信息:') # 不写encoding = 'utf-8'中文会乱码 with open('info.txt ...
- maven系列:简介和安装配置(Mac、Linux、Windows、settings.xml、IDEA配置)
目录 一.简介 二.安装 三.配置 Mac配置 Centos配置 Window配置 settings.xml配置 IDEA配置 一.简介 官网:https://maven.apache.org mav ...
- [Bread.Mvc] 开源一款自用 MVC 框架,支持 Native AOT
Bread.Mvc Bread.Mvc 是一款完全支持 Native AOT 的 MVC 框架,搭配同样支持 AOT 的 Avalonia,让你的开发事半功倍.项目开源在 Gitee,欢迎 Star. ...
- CodeForces 1187E Tree Painting
题意:给定一棵\(n\)个点的树 初始全是白点 要求你做\(n\)步操作,每一次选定一个与一个黑点相隔一条边的白点,将它染成黑点,然后获得该白点被染色前所在的白色联通块大小的权值. 第一次操作可以任意 ...
- centos8环境基本优化
centos8环境基本优化 目录 centos8环境基本优化 1.防火墙优化 2.源优化: 方案1.更换阿里源 方案2.使用centos8.5 源 安装epel源 3.ssh连接慢解决 4.关闭公网, ...
- Vue 搭配 Spring MVC 创建一个 web 项目
Vue 搭配 Spring MVC 创建一个 web 项目 想要写一个登录的web应用程序.页面使用Vue,后端使用Spring MVC,最终打成war包,放在tomcat下启动. 1.创建Sprin ...
- SpringBootAdmin_监控
监控的意义 监控服务状态是否宕机 监控服务运行指标(内存.虚拟机.线程.请求等) 监控日志 管理服务(服务下线) 监控的实施方式 大部分监控平台都是主动拉取监控信息,而不是被动地等待应用程序传递信息 ...
- 【AI 模型】首个 Joy 模型诞生!!!全民生成 Joy 大片
接上一篇文章 "只要10秒,AI生成IP海报,解放双手",这次是全网第一个"共享joy模型",真的赚到了! 经过这段时间无数次的探索.试错.实验,最终积累了非常 ...
- tiptopGP5.2链接所有表或报不存在函数处理
修改交易的表时需要特别注意,改完要关联所有有关的表r.rb.rb pja_file 当链接提示不存在的函数调用,又无法确定具体是那个关联程序时, 可以在本函数内先定义这个报错的函数,重新链接时,系统会 ...