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

在Zlib项目中的contrib目录下有一个minizip子项目,minizip实际上不是zlib库的一部分,而是一个独立的开源库,用于处理ZIP压缩文件格式。它提供了对ZIP文件的创建和解压的简单接口。minizip在很多情况下与zlib一起使用,因为ZIP压缩通常使用了DEFLATE压缩算法。通过对minizip库的二次封装则可实现针对目录的压缩与解压功能。

如果你想使用minizip通常你需要下载并编译它,然后将其链接到你的项目中。

编译Zlib库很简单,解压文件并进入到\zlib-1.3\contrib\vstudio目录下,根据自己编译器版本选择不同的目录,这里我选择vc12,进入后打开zlibvc.sln等待生成即可。

成功后可获得两个文件分别是zlibstat.libzlibwapi.lib如下图;

接着配置引用目录,这里需要多配置一个minizip头文件,该头文件是zlib里面的一个子项目。

lib库则需要包含zlibstat.libzlibwapi.lib这两个文件,此处读者可以自行放入到一个目录下;

ZIP 递归压缩目录

如下所示代码是一个使用zlib库实现的简单文件夹压缩工具的C++程序。该程序提供了压缩文件夹到 ZIP 文件的功能,支持递归地添加文件和子文件夹,利用了 Windows API 和 zlib 库的函数。

#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") bool nyAddfiletoZip(zipFile zfile, const std::string& fileNameinZip, const std::string& srcfile)
{
// 目录如果为空则直接返回
if (NULL == zfile || fileNameinZip.empty())
{
return 0;
} 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, "\\");
} nErr = zipOpenNewFileInZip(zfile, sznewfileName, &zinfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
if (nErr != ZIP_OK)
{
return false;
}
if (!srcfile.empty())
{
// 打开源文件
FILE* srcfp = _fsopen(srcfile.c_str(), "rb", _SH_DENYNO);
if (NULL == srcfp)
{
std::cout << "打开源文件失败" << std::endl;
return false;
} // 读入源文件写入zip文件
int numBytes = 0;
char* pBuf = new char[1024 * 100];
if (NULL == pBuf)
{
std::cout << "新建缓冲区失败" << std::endl;
return 0;
}
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);
}
zipCloseFileInZip(zfile); return true;
} 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
// 生成zip文件中的相对路径
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);
} nyAddfiletoZip(zfile, relativepath, szTemp); } while (::FindNextFileA(hFile, &findFileData));
FindClose(hFile); return true;
} /*
* 函数功能 : 压缩文件夹到目录
* 备 注 : dirpathName 源文件/文件夹
* zipFileName 目的压缩包
* parentdirName 压缩包内名字(文件夹名)
*/
bool nyCreateZipfromDir(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName)
{
bool bRet = false; /*
APPEND_STATUS_CREATE 创建追加
APPEND_STATUS_CREATEAFTER 创建后追加(覆盖方式)
APPEND_STATUS_ADDINZIP 直接追加
*/
zipFile zFile = NULL;
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)
{
std::cout << "创建ZIP文件失败" << std::endl;
return bRet;
} if (nyCollectfileInDirtoZip(zFile, dirpathName, parentdirName))
{
bRet = true;
} zipClose(zFile, NULL); return bRet;
}

主要功能

nyCreateZipfromDir函数

bool nyCreateZipfromDir(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName);

功能:压缩文件夹到指定的 ZIP 文件。

参数:

  • dirpathName:源文件夹路径。
  • zipfileName:目标 ZIP 文件路径。
  • parentdirName:在 ZIP 文件内的文件夹名(如果为空则不指定目录)。

nyCollectfileInDirtoZip 函数

bool nyCollectfileInDirtoZip(zipFile zfile, const std::string& filepath, const std::string& parentdirName);

功能:递归地收集文件夹中的文件,并将它们添加到已打开的 ZIP 文件中。

参数:

  • zfile:已打开的 ZIP 文件。
  • filepath:文件夹路径。
  • parentdirName:在 ZIP 文件内的相对文件夹名。

nyAddfiletoZip 函数

bool nyAddfiletoZip(zipFile zfile, const std::string& fileNameinZip, const std::string& srcfile);

功能:将指定文件添加到已打开的 ZIP 文件中。

参数:

  • zfile:已打开的 ZIP 文件。
  • fileNameinZip:在 ZIP 文件内的相对文件路径。
  • srcfile:源文件路径。

程序流程

  • 文件夹压缩参数设置: 用户提供源文件夹路径、目标 ZIP 文件路径,以及在 ZIP 文件内的文件夹名。
  • ZIP 文件打开: 根据目标 ZIP 文件是否存在,使用 zipOpen 函数打开 ZIP 文件。
  • 文件夹递归添加: 使用 nyCollectfileInDirtoZip 函数递归地收集文件夹中的文件,并通过 nyAddfiletoZip 函数将它们添加到 ZIP 文件中。
  • ZIP 文件关闭: 使用 zipClose 函数关闭 ZIP 文件。

示例用法

int main(int argc, char* argv[])
{
std::string dirpath = "D:\\lyshark\\test"; // 源文件/文件夹
std::string zipfileName = "D:\\lyshark\\test.zip"; // 目的压缩包 bool ref = nyCreateZipfromDir(dirpath, zipfileName, "lyshark"); // 包内文件名<如果为空则压缩时不指定目录> std::cout << "[LyShark] 压缩状态 " << ref << std::endl;
system("pause");
return 0;
}

上述调用代码,参数1指定为需要压缩的文件目录,参数2指定为需要压缩成目录名,参数3为压缩后该目录的名字。

ZIP 递归解压目录

在这个C++程序中,实现了递归解压缩ZIP文件的功能。程序提供了以下主要功能:

  • replace_all 函数: 用于替换字符串中的指定子串。
  • CreatedMultipleDirectory 函数: 用于创建多级目录,确保解压缩时的目录结构存在。
  • UnzipFile 函数: 用于递归解压缩 ZIP 文件。该函数打开 ZIP 文件,获取文件信息,然后逐个解析和处理 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") // 将字符串内的old_value替换成new_value
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;
} /*
* 函数功能 : 递归解压文件目录
* 备 注 : strFilePath 压缩包路径
* strTempPath 解压到
*/
void UnzipFile(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;
} // 获取zip文件的信息
unz_global_info* pGlobalInfo = new unz_global_info;
nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo);
if (nReturnValue != UNZ_OK)
{
std::cout << "数据包: " << pGlobalInfo->number_entry << endl;
return;
} // 解析zip文件
unz_file_info* pFileInfo = new unz_file_info;
char szZipFName[MAX_PATH] = { 0 };
char szExtraName[MAX_PATH] = { 0 };
char szCommName[MAX_PATH] = { 0 }; // 存放从zip中解析出来的内部文件名
for (int i = 0; i < pGlobalInfo->number_entry; i++)
{
// 解析得到zip中的文件信息
nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, szExtraName, MAX_PATH, szCommName, MAX_PATH);
if (nReturnValue != UNZ_OK)
return; std::cout << "解压文件名: " << szZipFName << endl; 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;
} // 打开文件
nReturnValue = unzOpenCurrentFile(unzfile);
if (nReturnValue != UNZ_OK)
{
CloseHandle(hFile);
return;
} // 读取文件
uLong BUFFER_SIZE = pFileInfo->uncompressed_size;;
void* szReadBuffer = NULL;
szReadBuffer = (char*)malloc(BUFFER_SIZE);
if (NULL == szReadBuffer)
{
break;
} while (TRUE)
{
memset(szReadBuffer, 0, BUFFER_SIZE);
int nReadFileSize = 0; nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE); // 读取文件失败
if (nReadFileSize < 0)
{
unzCloseCurrentFile(unzfile);
CloseHandle(hFile);
return;
}
// 读取文件完毕
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;
}
}
}
free(szReadBuffer);
}
unzGoToNextFile(unzfile);
} delete pFileInfo;
delete pGlobalInfo; // 关闭
if (unzfile)
{
unzClose(unzfile);
}
}

主要功能

replace_all 函数

std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value)

功能:在字符串 str 中替换所有的 old_value 为 new_value。

参数:

  • str:待处理的字符串。
  • old_value:要被替换的子串。
  • new_value:替换后的新子串。

返回值:替换后的字符串。

CreatedMultipleDirectory 函数

BOOL CreatedMultipleDirectory(const std::string& direct)

功能:创建多级目录,确保路径存在。

参数:

  • direct:目录路径。
  • 返回值:如果成功创建目录返回 TRUE,否则返回 FALSE。

UnzipFile 函数

void UnzipFile(const std::string& strFilePath, const std::string& strTempPath)

功能:递归解压缩 ZIP 文件。

参数:

  • strFilePath:ZIP 文件路径。
  • strTempPath:解压到的目标路径。

该函数打开 ZIP 文件,获取文件信息,然后逐个解析和处理 ZIP 文件中的文件或目录。在解析过程中,根据文件或目录的属性,创建相应的目录结构,然后将文件写入目标路径。

示例用法

int main(int argc, char* argv[])
{
std::string srcFilePath = "D:\\lyshark\\test.zip";
std::string tempdir = "D:\\lyshark\\test"; // 如果传入目录不存在则创建
if (!::PathFileExistsA(tempdir.c_str()))
{
CreatedMultipleDirectory(tempdir);
} // 调用解压函数
UnzipFile(srcFilePath, tempdir); system("pause");
return 0;
}

案例中,首先在解压缩之前判断传入目录是否存在,如果不存在则需要调用API创建目录,如果存在则直接调用UnzipFIle解压缩函数,实现解包,输出效果图如下;

C++ MiniZip实现目录压缩与解压的更多相关文章

  1. 【转】iOS开发之压缩与解压文件

    ziparchive是基于开源代码”MiniZip”的zip压缩与解压的Objective-C 的Class,使用起来非常的简单方法:从http://code.google.com/p/ziparch ...

  2. iOS开发之压缩与解压文件

    ziparchive是基于开源代码”MiniZip”的zip压缩与解压的Objective-C 的Class,使用起来非常的简单 方法:从http://code.google.com/p/ziparc ...

  3. 《OD学hadoop》在LINUX下如何将tar压缩文件解压到指定的目录下

    linux下tar命令解压到指定的目录 :#tar zxvf /bbs.tar.zip -C /zzz/bbs //把根目录下的bbs.tar.zip解压到/zzz/bbs下,前提要保证存在/zzz/ ...

  4. 文件操作工具类: 文件/目录的创建、删除、移动、复制、zip压缩与解压.

    FileOperationUtils.java package com.xnl.utils; import java.io.BufferedInputStream; import java.io.Bu ...

  5. golang zip 压缩,解压(含目录文件)

    每天学习一点go src. 今天学习了zip包的简单使用,实现了含目录的压缩与解压. 写了两个方法,实现了压缩.解压. package ziptest import ( "archive/z ...

  6. golang tar gzip 压缩,解压(含目录文件)

    tar是用于文件归档,gzip用于压缩.仅仅用tar的话,达不到压缩的目的.我们常见的tar.gz就是用gzip压缩生成的tar归档文件. go实现tar压缩与解压与zip类似,区别在于tar需要使用 ...

  7. C#调用RAR压缩与解压

    public void RARsave(string rarPatch, string rarFiles,string  patch,string rarName)        {          ...

  8. Linux压缩与解压常用命令

    欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...

  9. Java实现文件压缩与解压

    Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个文件和任意级联文件夹进行压缩和解压,对于一些初学者来说是个很不错的实例.(转载自http://www.puiedu. ...

  10. Zip 压缩、解压技术在 HTML5 浏览器中的应用

    JSZip 是一款可以创建.读取.修改 .zip 文件的 javaScript 工具.在 web 应用中,免不了需要从 web 服务器中获取资源,如果可以将所有的资源都合并到一个 .zip 文件中,这 ...

随机推荐

  1. OpenUSD联盟:塑造元宇宙的3D未来

    一.引言 近日,美国3D内容行业的五家主要公司苹果.英伟达.皮克斯.Adobe和Autodesk联合成立了OpenUSD联盟(AOUSD).这一联盟的成立标志着元宇宙领域的一次重要合作,旨在制定元宇宙 ...

  2. 超详细的mysql总结(DQL)

    上一篇文章总结了 DDL.DML的使用,这一篇文章把剩下的 DQL 加上~   DQL(Data Query Language)即数据库查询语言,用来查询所需要的信息,在查询的过程中,需要判断所查询的 ...

  3. ros源的移除

    在Ubuntu上卸载了ros系统后,每次运行源更新命令 sudo apt update 都会报错,提示ros源找不到等问题. 这时,只需要 cd /etc/apt/souce.list.d sudo ...

  4. elasticsearch中的数据类型search_as_you_type及查看底层Lucene索引

    search_as_you_type字段类型用于自动补全,当用户输入搜索关键词的时候,还没输完就可以提示用户相关内容.as_you_type应该是说当你打字的时候.它会给索引里的这个类型的字段添加一些 ...

  5. Android13深入了解 Android 小窗口模式和窗口类型

    Android13深入了解 Android 小窗口模式和窗口类型 小窗模式,作为一种在移动设备上的多任务处理方式,为用户带来了便捷和高效的体验,尤其在一些特定场景下,其价值愈发凸显.以下是为什么需要小 ...

  6. 04.使用 github actions+docker 自动部署前后端分离项目 zhontai (.net core+vue)

    前言 Github Actions是什么?是 GitHub 提供的一种持续集成/持续部署(CI/CD)工作流程自动化服务,助力项目的自动化构建.测试和部署. 依托于平台,本文将分享使用 GitHub ...

  7. 【译】在 Visual Studio 中处理图像变得更容易了

    任何 Web.桌面或移动开发人员都经常使用图像.你可以从 C#.HTML.XAML.CSS.C++.TypeScript 甚至代码注释中引用它们.有些图像是本地的,有些存在于线上或网络共享中,而其他图 ...

  8. 为什么创建 Redis 集群时会自动错开主从节点?

    哈喽大家好,我是咸鱼 在<一台服务器上部署 Redis 伪集群>这篇文章中,咸鱼在创建 Redis 集群时并没有明确指定哪个 Redis 实例将担任 master,哪个将担任 slave ...

  9. [面向对象] 魔术方法 (__set, __get, __unset, __isset)

    __set, __get,__isset, __unset 是面向对象里用来友操作的魔术方法.  先看看使用方法 echo $类->属性;  //取不存在属性或私有保护属性时,  以下方法被调用 ...

  10. Python ChatGPT Telegram Bot

    注册 这里如何注册我就不说明了,大家自行去注册,主要是现在GPT的基本上已经备用很多了,导致了接码的价格也上涨了,而且使用token的话,其实还是很快可以用完免费的18美金: 接码:https://s ...