5,086
社区成员




Zlib是一个开源的数据压缩库,提供了一种通用的数据压缩和解压缩算法。它最初由Jean-Loup Gailly
和Mark 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.lib
和zlibwapi.lib
如下图;
接着配置引用目录,这里需要多配置一个minizip
头文件,该头文件是zlib里面的一个子项目。
lib库则需要包含zlibstat.lib
和zlibwapi.lib
这两个文件,此处读者可以自行放入到一个目录下;
如下所示代码是一个使用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 文件。
参数:
nyCollectfileInDirtoZip 函数
bool nyCollectfileInDirtoZip(zipFile zfile, const std::string& filepath, const std::string& parentdirName);
功能:递归地收集文件夹中的文件,并将它们添加到已打开的 ZIP 文件中。
参数:
nyAddfiletoZip 函数
bool nyAddfiletoZip(zipFile zfile, const std::string& fileNameinZip, const std::string& srcfile);
功能:将指定文件添加到已打开的 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为压缩后该目录的名字。
在这个C++程序中,实现了递归解压缩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。
参数:
返回值:替换后的字符串。
CreatedMultipleDirectory 函数
- BOOL CreatedMultipleDirectory(const std::string& direct)
功能:创建多级目录,确保路径存在。
参数:
UnzipFile 函数
- void UnzipFile(const std::string& strFilePath, const std::string& strTempPath)
功能:递归解压缩 ZIP 文件。
参数:
该函数打开 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
解压缩函数,实现解包,输出效果图如下;