经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C/C++ Zlib库封装MyZip压缩类
来源:cnblogs  作者:微软技术分享  时间:2023/11/29 16:15:30  对本文有异议

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

在软件开发中,文件的压缩和解压缩是一项常见的任务,而ZIP是一种被广泛应用的压缩格式。为了方便地处理ZIP压缩和解压缩操作,开发者通常使用各种编程语言和库来实现这些功能。本文将聚焦于一个简化的C++实现,通过分析代码,我们将深入了解其设计和实现细节。

类的功能实现

MyZip类旨在提供简单易用的ZIP压缩和解压缩功能。通过成员函数CompressUnCompress,该类使得对目录的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压缩和解压缩功能,并可以在项目中被应用,该类代码如下所示;

  1. #define ZLIB_WINAPI
  2. #include <string>
  3. #include <iostream>
  4. #include <vector>
  5. #include <Shlwapi.h>
  6. #include <zip.h>
  7. #include <unzip.h>
  8. #include <zlib.h>
  9. using namespace std;
  10. #pragma comment(lib, "Shlwapi.lib")
  11. #pragma comment(lib, "zlibstat.lib")
  12. class MyZip
  13. {
  14. private:
  15. // 向ZIP文件中添加文件
  16. bool nyAddfiletoZip(zipFile zfile, const std::string& fileNameinZip, const std::string& srcfile)
  17. {
  18. if (NULL == zfile || fileNameinZip.empty())
  19. {
  20. return false;
  21. }
  22. int nErr = 0;
  23. zip_fileinfo zinfo = { 0 };
  24. tm_zip tmz = { 0 };
  25. zinfo.tmz_date = tmz;
  26. zinfo.dosDate = 0;
  27. zinfo.internal_fa = 0;
  28. zinfo.external_fa = 0;
  29. // 构建新文件名
  30. char sznewfileName[MAX_PATH] = { 0 };
  31. memset(sznewfileName, 0x00, sizeof(sznewfileName));
  32. strcat_s(sznewfileName, fileNameinZip.c_str());
  33. if (srcfile.empty())
  34. {
  35. strcat_s(sznewfileName, "\\");
  36. }
  37. // 在ZIP中打开新文件
  38. nErr = zipOpenNewFileInZip(zfile, sznewfileName, &zinfo, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
  39. if (nErr != ZIP_OK)
  40. {
  41. return false;
  42. }
  43. // 如果有源文件,读取并写入ZIP文件
  44. if (!srcfile.empty())
  45. {
  46. FILE* srcfp = _fsopen(srcfile.c_str(), "rb", _SH_DENYNO);
  47. if (NULL == srcfp)
  48. {
  49. return false;
  50. }
  51. int numBytes = 0;
  52. char* pBuf = new char[1024 * 100];
  53. if (NULL == pBuf)
  54. {
  55. return false;
  56. }
  57. // 逐块读取源文件并写入ZIP
  58. while (!feof(srcfp))
  59. {
  60. memset(pBuf, 0x00, sizeof(pBuf));
  61. numBytes = fread(pBuf, 1, sizeof(pBuf), srcfp);
  62. nErr = zipWriteInFileInZip(zfile, pBuf, numBytes);
  63. if (ferror(srcfp))
  64. {
  65. break;
  66. }
  67. }
  68. delete[] pBuf;
  69. fclose(srcfp);
  70. }
  71. // 关闭ZIP文件中的当前文件
  72. zipCloseFileInZip(zfile);
  73. return true;
  74. }
  75. // 递归地将目录下的文件添加到ZIP
  76. bool nyCollectfileInDirtoZip(zipFile zfile, const std::string& filepath, const std::string& parentdirName)
  77. {
  78. if (NULL == zfile || filepath.empty())
  79. {
  80. return false;
  81. }
  82. bool bFile = false;
  83. std::string relativepath = "";
  84. WIN32_FIND_DATAA findFileData;
  85. char szpath[MAX_PATH] = { 0 };
  86. if (::PathIsDirectoryA(filepath.c_str()))
  87. {
  88. strcpy_s(szpath, sizeof(szpath) / sizeof(szpath[0]), filepath.c_str());
  89. int len = strlen(szpath) + strlen("\\*.*") + 1;
  90. strcat_s(szpath, len, "\\*.*");
  91. }
  92. else
  93. {
  94. bFile = true;
  95. strcpy_s(szpath, sizeof(szpath) / sizeof(szpath[0]), filepath.c_str());
  96. }
  97. HANDLE hFile = ::FindFirstFileA(szpath, &findFileData);
  98. if (NULL == hFile)
  99. {
  100. return false;
  101. }
  102. do
  103. {
  104. // 构建相对路径
  105. if (parentdirName.empty())
  106. relativepath = findFileData.cFileName;
  107. else
  108. relativepath = parentdirName + "\\" + findFileData.cFileName;
  109. // 如果是目录,递归处理子目录
  110. if (findFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
  111. {
  112. if (strcmp(findFileData.cFileName, ".") != 0 && strcmp(findFileData.cFileName, "..") != 0)
  113. {
  114. nyAddfiletoZip(zfile, relativepath, "");
  115. char szTemp[MAX_PATH] = { 0 };
  116. strcpy_s(szTemp, filepath.c_str());
  117. strcat_s(szTemp, "\\");
  118. strcat_s(szTemp, findFileData.cFileName);
  119. nyCollectfileInDirtoZip(zfile, szTemp, relativepath);
  120. }
  121. continue;
  122. }
  123. char szTemp[MAX_PATH] = { 0 };
  124. if (bFile)
  125. {
  126. strcpy_s(szTemp, filepath.c_str());
  127. }
  128. else
  129. {
  130. strcpy_s(szTemp, filepath.c_str());
  131. strcat_s(szTemp, "\\");
  132. strcat_s(szTemp, findFileData.cFileName);
  133. }
  134. // 将文件添加到ZIP
  135. nyAddfiletoZip(zfile, relativepath, szTemp);
  136. } while (::FindNextFileA(hFile, &findFileData));
  137. FindClose(hFile);
  138. return true;
  139. }
  140. // 替换字符串中的所有指定子串
  141. std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value)
  142. {
  143. while (true)
  144. {
  145. std::string::size_type pos(0);
  146. if ((pos = str.find(old_value)) != std::string::npos)
  147. str.replace(pos, old_value.length(), new_value);
  148. else
  149. break;
  150. }
  151. return str;
  152. }
  153. // 创建多级目录
  154. BOOL CreatedMultipleDirectory(const std::string& direct)
  155. {
  156. std::string Directoryname = direct;
  157. if (Directoryname[Directoryname.length() - 1] != '\\')
  158. {
  159. Directoryname.append(1, '\\');
  160. }
  161. std::vector< std::string> vpath;
  162. std::string strtemp;
  163. BOOL bSuccess = FALSE;
  164. // 遍历目录字符串,逐级创建目录
  165. for (int i = 0; i < Directoryname.length(); i++)
  166. {
  167. if (Directoryname[i] != '\\')
  168. {
  169. strtemp.append(1, Directoryname[i]);
  170. }
  171. else
  172. {
  173. vpath.push_back(strtemp);
  174. strtemp.append(1, '\\');
  175. }
  176. }
  177. std::vector< std::string>::iterator vIter = vpath.begin();
  178. for (; vIter != vpath.end(); vIter++)
  179. {
  180. bSuccess = CreateDirectoryA(vIter->c_str(), NULL) ? TRUE : FALSE;
  181. }
  182. return bSuccess;
  183. }
  184. public:
  185. // 压缩目录
  186. bool Compress(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName)
  187. {
  188. bool bRet = false;
  189. zipFile zFile = NULL;
  190. // 根据ZIP文件是否存在选择打开方式
  191. if (!::PathFileExistsA(zipfileName.c_str()))
  192. {
  193. zFile = zipOpen(zipfileName.c_str(), APPEND_STATUS_CREATE);
  194. }
  195. else
  196. {
  197. zFile = zipOpen(zipfileName.c_str(), APPEND_STATUS_ADDINZIP);
  198. }
  199. if (NULL == zFile)
  200. {
  201. return bRet;
  202. }
  203. // 将目录下的文件添加到ZIP
  204. if (nyCollectfileInDirtoZip(zFile, dirpathName, parentdirName))
  205. {
  206. bRet = true;
  207. }
  208. zipClose(zFile, NULL);
  209. return bRet;
  210. }
  211. // 解压目录
  212. bool UnCompress(const std::string& strFilePath, const std::string& strTempPath)
  213. {
  214. int nReturnValue;
  215. string tempFilePath;
  216. string srcFilePath(strFilePath);
  217. string destFilePath;
  218. // 打开ZIP文件
  219. unzFile unzfile = unzOpen(srcFilePath.c_str());
  220. if (unzfile == NULL)
  221. {
  222. return false;
  223. }
  224. unz_global_info* pGlobalInfo = new unz_global_info;
  225. nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo);
  226. if (nReturnValue != UNZ_OK)
  227. {
  228. return false;
  229. }
  230. unz_file_info* pFileInfo = new unz_file_info;
  231. char szZipFName[MAX_PATH] = { 0 };
  232. char szExtraName[MAX_PATH] = { 0 };
  233. char szCommName[MAX_PATH] = { 0 };
  234. for (int i = 0; i < pGlobalInfo->number_entry; i++)
  235. {
  236. nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, szExtraName, MAX_PATH, szCommName, MAX_PATH);
  237. if (nReturnValue != UNZ_OK)
  238. return false;
  239. string strZipFName = szZipFName;
  240. // 如果是目录,创建相应目录
  241. if (pFileInfo->external_fa == FILE_ATTRIBUTE_DIRECTORY || (strZipFName.rfind('/') == strZipFName.length() - 1))
  242. {
  243. destFilePath = strTempPath + "//" + szZipFName;
  244. CreateDirectoryA(destFilePath.c_str(), NULL);
  245. }
  246. else
  247. {
  248. string strFullFilePath;
  249. tempFilePath = strTempPath + "/" + szZipFName;
  250. strFullFilePath = tempFilePath;
  251. int nPos = tempFilePath.rfind("/");
  252. int nPosRev = tempFilePath.rfind("\\");
  253. if (nPosRev == string::npos && nPos == string::npos)
  254. continue;
  255. size_t nSplitPos = nPos > nPosRev ? nPos : nPosRev;
  256. destFilePath = tempFilePath.substr(0, nSplitPos + 1);
  257. // 创建多级目录
  258. if (!PathIsDirectoryA(destFilePath.c_str()))
  259. {
  260. destFilePath = replace_all(destFilePath, "/", "\\");
  261. int bRet = CreatedMultipleDirectory(destFilePath);
  262. }
  263. strFullFilePath = replace_all(strFullFilePath, "/", "\\");
  264. // 创建文件并写入数据
  265. HANDLE hFile = CreateFileA(strFullFilePath.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
  266. if (hFile == INVALID_HANDLE_VALUE)
  267. {
  268. return false;
  269. }
  270. nReturnValue = unzOpenCurrentFile(unzfile);
  271. if (nReturnValue != UNZ_OK)
  272. {
  273. CloseHandle(hFile);
  274. return false;
  275. }
  276. uLong BUFFER_SIZE = pFileInfo->uncompressed_size;
  277. void* szReadBuffer = NULL;
  278. szReadBuffer = (char*)malloc(BUFFER_SIZE);
  279. if (NULL == szReadBuffer)
  280. {
  281. break;
  282. }
  283. // 逐块读取ZIP文件并写入目标文件
  284. while (TRUE)
  285. {
  286. memset(szReadBuffer, 0, BUFFER_SIZE);
  287. int nReadFileSize = 0;
  288. nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE);
  289. if (nReadFileSize < 0)
  290. {
  291. unzCloseCurrentFile(unzfile);
  292. CloseHandle(hFile);
  293. return false;
  294. }
  295. else if (nReadFileSize == 0)
  296. {
  297. unzCloseCurrentFile(unzfile);
  298. CloseHandle(hFile);
  299. break;
  300. }
  301. else
  302. {
  303. DWORD dWrite = 0;
  304. BOOL bWriteSuccessed = WriteFile(hFile, szReadBuffer, BUFFER_SIZE, &dWrite, NULL);
  305. if (!bWriteSuccessed)
  306. {
  307. unzCloseCurrentFile(unzfile);
  308. CloseHandle(hFile);
  309. return false;
  310. }
  311. }
  312. }
  313. free(szReadBuffer);
  314. }
  315. unzGoToNextFile(unzfile);
  316. }
  317. delete pFileInfo;
  318. delete pGlobalInfo;
  319. if (unzfile)
  320. {
  321. unzClose(unzfile);
  322. }
  323. return true;
  324. }
  325. };

如何使用类

压缩文件时可以通过调用zip.Compress()函数实现,该函数接受3个参数,第一个参数是需要压缩的目录名,第二个参数是压缩后保存的文件名,第三个参数则是压缩后主目录的名字,我们以压缩D:\\csdn目录下的所有文件为例,代码如下所示;

  1. int main(int argc, char* argv[])
  2. {
  3. MyZip zip;
  4. // 压缩目录
  5. std::string compress_src = "D:\\csdn"; // 压缩目录
  6. std::string compress_dst = "D:\\test.zip"; // 压缩后
  7. bool compress_flag = zip.Compress(compress_src, compress_dst, "lyshark");
  8. std::cout << "压缩状态: " << compress_flag << std::endl;
  9. system("pause");
  10. return 0;
  11. }

压缩后可以看到对应的压缩包内容,如下所示;

解压缩与压缩类似,通过调用zip.UnCompress实现,该方法需要传入两个参数,被压缩的文件名和解压到的目录名,如果目录不存在则会创建并解压。

  1. int main(int argc, char* argv[])
  2. {
  3. MyZip zip;
  4. // 解压缩目录
  5. std::string uncompress_src = "D:\\test.zip"; // 被解压文件
  6. std::string uncompress_dst = "D:\\dst"; // 解压到
  7. bool compress_flag = zip.UnCompress(uncompress_src, uncompress_dst);
  8. std::cout << "解压缩状态: " << compress_flag << std::endl;
  9. system("pause");
  10. return 0;
  11. }

输出效果如下所示;

原文链接:https://www.cnblogs.com/LyShark/p/17865137.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号