C/C++ Zlib庫封裝MyZip壓縮類的詳細(xì)過程
Zlib是一個開源的數(shù)據(jù)壓縮庫,提供了一種通用的數(shù)據(jù)壓縮和解壓縮算法。它最初由Jean-Loup Gailly和Mark Adler開發(fā),旨在成為一個高效、輕量級的壓縮庫,其被廣泛應(yīng)用于許多領(lǐng)域,包括網(wǎng)絡(luò)通信、文件壓縮、數(shù)據(jù)庫系統(tǒng)等。其壓縮算法是基于DEFLATE算法,這是一種無損數(shù)據(jù)壓縮算法,通常能夠提供相當(dāng)高的壓縮比。
在軟件開發(fā)中,文件的壓縮和解壓縮是一項(xiàng)常見的任務(wù),而ZIP是一種被廣泛應(yīng)用的壓縮格式。為了方便地處理ZIP壓縮和解壓縮操作,開發(fā)者通常使用各種編程語言和庫來實(shí)現(xiàn)這些功能。本文將聚焦于一個簡化的C++實(shí)現(xiàn),通過分析代碼,我們將深入了解其設(shè)計和實(shí)現(xiàn)細(xì)節(jié)。
類的功能實(shí)現(xiàn)
MyZip
類旨在提供簡單易用的ZIP壓縮和解壓縮功能。通過成員函數(shù)Compress
和UnCompress
,該類使得對目錄的ZIP壓縮和ZIP文件的解壓變得相對容易。
ZIP壓縮函數(shù) Compress
Compress
函數(shù)通過zlib庫提供的ZIP壓縮功能,遞歸地將目錄下的文件添加到ZIP文件中。其中,nyCollectfileInDirtoZip
函數(shù)負(fù)責(zé)遍歷目錄,而nyAddfiletoZip
函數(shù)則用于添加文件到ZIP中。這種設(shè)計使得代碼模塊化,易于理解。
ZIP解壓函數(shù) UnCompress
UnCompress
函數(shù)通過zlib庫提供的ZIP解壓功能,將ZIP文件解壓到指定目錄。函數(shù)中使用了unz
系列函數(shù)來遍歷ZIP文件中的文件信息,并根據(jù)文件類型進(jìn)行相應(yīng)的處理。這包括創(chuàng)建目錄和寫入文件,使得解壓后的目錄結(jié)構(gòu)與ZIP文件一致。
將如上的壓縮與解壓方法封裝成MyZip
類,調(diào)用zip.Compress()
實(shí)現(xiàn)壓縮目錄,調(diào)用zip.UnCompress()
則實(shí)現(xiàn)解壓縮目錄。這些函數(shù)使用了zlib庫的ZIP壓縮和解壓縮功能,并可以在項(xiàng)目中被應(yīng)用,該類代碼如下所示;
#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; // 構(gòu)建新文件名 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); } // 關(guān)閉ZIP文件中的當(dāng)前文件 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 { // 構(gòu)建相對路徑 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; } // 創(chuàng)建多級目錄 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; // 遍歷目錄字符串,逐級創(chuàng)建目錄 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; // 根據(jù)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; // 如果是目錄,創(chuàng)建相應(yīng)目錄 if (pFileInfo->external_fa == FILE_ATTRIBUTE_DIRECTORY || (strZipFName.rfind('/') == strZipFName.length() - 1)) { destFilePath = strTempPath + "http://" + 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); // 創(chuàng)建多級目錄 if (!PathIsDirectoryA(destFilePath.c_str())) { destFilePath = replace_all(destFilePath, "/", "\\"); int bRet = CreatedMultipleDirectory(destFilePath); } strFullFilePath = replace_all(strFullFilePath, "/", "\\"); // 創(chuàng)建文件并寫入數(shù)據(jù) 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文件并寫入目標(biāo)文件 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; } };
如何使用類
壓縮文件時可以通過調(diào)用zip.Compress()
函數(shù)實(shí)現(xiàn),該函數(shù)接受3個參數(shù),第一個參數(shù)是需要壓縮的目錄名,第二個參數(shù)是壓縮后保存的文件名,第三個參數(shù)則是壓縮后主目錄的名字,我們以壓縮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 << "壓縮狀態(tài): " << compress_flag << std::endl; system("pause"); return 0; }
壓縮后可以看到對應(yīng)的壓縮包內(nèi)容,如下所示;
解壓縮與壓縮類似,通過調(diào)用zip.UnCompress
實(shí)現(xiàn),該方法需要傳入兩個參數(shù),被壓縮的文件名和解壓到的目錄名,如果目錄不存在則會創(chuàng)建并解壓。
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 << "解壓縮狀態(tài): " << compress_flag << std::endl; system("pause"); return 0; }
輸出效果如下所示;
到此這篇關(guān)于C/C++ Zlib庫封裝MyZip壓縮類的文章就介紹到這了,更多相關(guān)C++封裝Zlib庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言中g(shù)etchar()與putchar()函數(shù)詳解
本文主要介紹了C語言中g(shù)etchar()與putchar()函數(shù)詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01OpenCV中的cv::Mat函數(shù)將數(shù)據(jù)寫入txt文件
這篇文章主要介紹了OpenCVcv::Mat中的數(shù)據(jù)按行列寫入txt文件中,需要的朋友可以參考下2018-05-05