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 Gailly和Mark Adler开发,旨在成为一个高效、轻量级的压缩库,其被广泛应用于许多领域,包括网络通信、文件压缩、数据库系统等。其压缩算法是基于DEFLATE算法,这是一种无损数据压缩算法,通常能够提供相当高的压缩比。
在软件开发中,文件的压缩和解压缩是一项常见的任务,而ZIP是一种被广泛应用的压缩格式。为了方便地处理ZIP压缩和解压缩操作,开发者通常使用各种编程语言和库来实现这些功能。本文将聚焦于一个简化的C++`实现,通过分析代码,我们将深入了解其设计和实现细节。
1.1、类的功能实现
MyZip类旨在提供简单易用的ZIP压缩和解压缩功能。通过成员函数Compress和UnCompress,该类使得对目录的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 #include #include #include #include #include #include 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; } // 逐块读取源文件并写入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 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; else relativepath = 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); } // 将文件添加到ZIP AddfiletoZip(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 vpath; std::string strtemp; BOOL bSuccess = FALSE; // 遍历目录字符串,逐级创建目录 for (int i = 0; i ::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 (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 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
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 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