C++ 使用zlib开源库的minizip解压缩文件及文件夹
首先 GitHub 上下载 zlib 的发行版本进行编译;
如果出现 zlib报“LNK2001:无法解析的外部符号”错误 的情况,是因为编译zlib(dll)的工程默认有预处理器定义ZLIB_WINAPI,ZEXPORT在zconf.h中的定义为WINAPI:
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
# define ZEXPORTVA FAR CDECL
# endif
# endif#define WINAPI __stdcall
所以,zlib(dll)的导出函数调用约定为__stdcall,和zlib(dll)的导入函数调用约定__cdecl不一致。
针对zlib编译dll文件编译出错,有以下两种解决办法:
1. 在zlivc工程中去掉预处理器定义ZLIB_WINAPI(预处理定义:vs工程属性->C/C++->预处理器)
去掉该定义后,宏定义ZEXPORT在zconf.h文件中实际定义如下:
#ifndef ZEXPORT
# define ZEXPORT
#endif
// 所以导出函数unzGoToNextFile
extern int ZEXPORT unzGoToNextFile (unzFile file)// 等价于
extern int unzGoToNextFile (unzFile file)// 也等价于(vs默认是__cdecl函数调用约定)
extern int __cdecl unzGoToNextFile (unzFile file)
所以在新的工程中导入zlib相关的库文件和dll文件后,编译dll的工程和引入dll的工程的函数调用约定均为__cdecl方式,导出函数能够正确解析了,编译自然就通过了。由上宏定义注释可知,标准编译ZLIB1.DLL是没有ZLIB_WINAPI预处理定义的,函数调用约定也是__cdecl,所以这里推荐该解决方案。
2. 在引入zlib工程中添加预处理器定义ZLIB_WINAPI
在引入dll工程中添加ZLIB_WINAPI定义后,宏定义ZEXPORT在zconf.h文件中实际定义如下:
#define ZEXPORT WINAPI#define WINAPI __stdcall
与导出zlib的dll工程均为__stdcall函数调用约定,编译也能顺利通过。
zlibHelper.h
#pragma once
#include <iostream>
#include <string>
#include "zip.h"
#include "unzip.h"
#include "zlib.h"class CZlibHelper
{
public:CZlibHelper();~CZlibHelper();//主要的压缩函数//将文件添加到zip文件,若zip文件已存在,则覆盖该文件static bool CreateZipfromDir(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName);//将文件添加到zip文件,若该zip文件不存在则创建一个zip文件static bool CreateZipfromDir2(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName);//主要的解压函数static bool UnzipFile(const std::string& strFilePath, const std::string& strTempPath);private://添加文件和文件夹到static bool AddfiletoZip(zipFile zfile, const std::string& fileNameinZip, const std::string& srcfile);static bool CollectfileInDirtoZip(zipFile zfile, const std::string& filepath, const std::string& parentdirName);//字符串 字符替换功能函数static std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value);//创建多级目录static bool CreatedMultipleDirectory(const std::string& direct);
};
zlibHelper.cpp
#include "stdafx.h"
#include <vector>
#include <fstream>
#include <sstream>
#include <Shlwapi.h> //#include "zip.h"
//#include "unzip.h"
//#include "zlib.h"#include "zlibHelper.h"using namespace std;
#pragma comment(lib, "Shlwapi.lib")CZlibHelper::CZlibHelper()
{
}CZlibHelper::~CZlibHelper()
{
}/*
* 函 数 :AddfiletoZip
* 函数功能 :添加文件到要打包的zipFile对象的文件里
* 参数备注 :参数zfile 表示zipFile文件对象
* 参数fileNameinZip 表示要压缩的文件路径
* 参数srcfile 表示要压缩的文件(为空表示为空目录)
*/
bool CZlibHelper::AddfiletoZip(zipFile zfile, const std::string& fileNameinZip, const std::string& srcfile)
{if (NULL == zfile || fileNameinZip.empty()/* || srcfile.empty()为空代表空目录*/){OutputDebugString("ZKTeco-AddfiletoZip--压缩路径为空");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){std::string strLog = "ZKTeco-AddfiletoZip--zipOpenNewFileInZip failed! error = ";strLog += std::to_string(nErr);OutputDebugString(strLog.c_str());return false;}if (!srcfile.empty()){//打开源文件FILE* srcfp = _fsopen(srcfile.c_str(), "rb", _SH_DENYNO);if (NULL == srcfp){//std::cout << "Open source file failed." << std::endl;std::string strLog = "ZKTeco-AddfiletoZip--Open source file failed. error = ";int nErr = GetLastError();strLog += std::to_string(nErr);OutputDebugString(strLog.c_str());return false;}//读入源文件写入zip文件int numBytes = 0;char* pBuf = new char[1024 * 100];if (NULL == pBuf){//std::cout << "new buffer failed." << std::endl;std::string strLog = "ZKTeco-AddfiletoZip--New buffer failed. error = ";int nErr = GetLastError();strLog += std::to_string(nErr);OutputDebugString(strLog.c_str());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;}}if (pBuf){delete[] pBuf;pBuf = NULL;}if (srcfp){fclose(srcfp);srcfp = NULL;}}zipCloseFileInZip(zfile);return true;
}/*
* 函 数 :CollectfileInDirtoZip
* 函数功能 :添加文件到要打包的zipFile对象的文件里
* 参数备注 :参数zfile 表示zipFile文件对象
* 参数fileNameinZip 表示要压缩的文件路径
* 参数srcfile 表示要压缩的文件(为空表示为空目录)
*/
bool CZlibHelper::CollectfileInDirtoZip(zipFile zfile, const std::string& filepath, const std::string& parentdirName)
{if (NULL == zfile || filepath.empty()){printf("zfile or filepath are null.");OutputDebugString("ZKTeco-CollectfileInDirtoZip--zfile or filepath are null."); return false;}bool bFile = false;std::string relativepath = "";WIN32_FIND_DATAA findFileData;memset(&findFileData, 0x0, sizeof(WIN32_FIND_DATAA));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){printf("FindFirstFile failed.");std::string strLog = "ZKTeco-CollectfileInDirtoZip--FindFirstFile failed. error = ";int nErr = GetLastError();strLog += std::to_string(nErr);OutputDebugString(strLog.c_str());return false;}do{if (parentdirName.empty()){relativepath = findFileData.cFileName;}else{relativepath = parentdirName + "\\" + findFileData.cFileName;//生成zip文件中的相对路径}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);}AddfiletoZip(zfile, relativepath, szTemp);} while (::FindNextFileA(hFile, &findFileData));FindClose(hFile);return true;
}
/*
* 压缩函数 :CreateZipfromDir
* 函数功能 :压缩zip、rar文件
* 参数备注 :参数dirpathName 表示要压缩的文件路径
* 参数zipfileName 表示要压缩的文件名称
* 参数parentdirName 表示要压缩的文件创建父目录(为空代表空目录,不创建父目录)
*/
bool CZlibHelper::CreateZipfromDir(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName)
{bool bRet = false;/* zipOpen 参数注释* 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);zFile = zipOpen(zipfileName.c_str(), APPEND_STATUS_CREATEAFTER);}if (NULL == zFile){std::cout << "create zip file failed." << std::endl;OutputDebugString("ZKTeco-CreateZipfromDir--zipOpen failed.");return bRet;}if (CollectfileInDirtoZip(zFile, dirpathName, parentdirName)){bRet = true;}zipClose(zFile, NULL);return bRet;
}/*
* 压缩函数 :CreateZipfromDir
* 函数功能 :压缩zip、rar文件
* 参数备注 :参数dirpathName 表示要压缩的文件路径
* 参数zipfileName 表示要压缩的文件名称
* 参数parentdirName 表示要压缩的文件创建父目录(为空代表空目录,不创建父目录)
*/
bool CZlibHelper::CreateZipfromDir2(const std::string& dirpathName, const std::string& zipfileName, const std::string& parentdirName)
{bool bRet = false;/* zipOpen 参数注释* 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);//zFile = zipOpen(zipfileName.c_str(), APPEND_STATUS_CREATEAFTER);}if (NULL == zFile){//std::cout << "create zip file failed." << std::endl;OutputDebugString("ZKTeco-CreateZipfromDir--zipOpen failed.");return bRet;}if (CollectfileInDirtoZip(zFile, dirpathName, parentdirName)){bRet = true;}zipClose(zFile, NULL);return bRet;
}bool CZlibHelper::UnzipFile(const std::string& strFilePath, const std::string& strTempPath)
{int nReturnValue;string tempFilePath;string srcFilePath(strFilePath);string destFilePath;std::cout << "Start unpacking the package... " << endl;if (!::PathFileExistsA(strTempPath.c_str())){CreatedMultipleDirectory(strTempPath);}//打开zip文件unzFile unzfile = unzOpen(srcFilePath.c_str());if (unzfile == NULL){printf("unzOpen failed.");OutputDebugString("ZKTeco-UnzipFile--unzOpen failed.");return false;}//获取zip文件的信息unz_global_info* pGlobalInfo = new unz_global_info;nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo);if (nReturnValue != UNZ_OK){printf("unzGetGlobalInfo failed.");//std::cout << "The number of compressed package files is " << pGlobalInfo->number_entry << endl;std::string strLog = "ZKTeco-UnzipFile--unzGetGlobalInfo failed. error = ";strLog += std::to_string(nReturnValue);OutputDebugString(strLog.c_str());return false;}//解析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 < (int)pGlobalInfo->number_entry; i++){//解析得到zip中的文件信息nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, szExtraName, MAX_PATH, szCommName, MAX_PATH);if (nReturnValue != UNZ_OK){printf("unzGetCurrentFileInfo failed.");std::string strLog = "ZKTeco-UnzipFile--unzGetCurrentFileInfo failed. error = ";strLog += std::to_string(nReturnValue);OutputDebugString(strLog.c_str());return false;} std::cout << "ZipName: " << szZipFName << " Extra: " << szExtraName << " Comm: " << szCommName << 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_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);if (hFile == INVALID_HANDLE_VALUE){int nErr = GetLastError();if (!::PathFileExistsA(strFullFilePath.c_str()))//如果目录已经存在,则跳过,不在重新创建{return false;}}//打开文件nReturnValue = unzOpenCurrentFile(unzfile);if (nReturnValue != UNZ_OK){CloseHandle(hFile);printf("unzOpenCurrentFile failed.");std::string strLog = "ZKTeco-UnzipFile--unzOpenCurrentFile failed. error = ";strLog += std::to_string(nReturnValue);OutputDebugString(strLog.c_str());return false;}//读取文件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);printf("读取文件失败");break;}else if (nReadFileSize == 0) //读取文件完毕{unzCloseCurrentFile(unzfile);CloseHandle(hFile);printf("读取文件完毕");break;}else //写入读取的内容{DWORD dWrite = 0;BOOL bWriteSuccessed = WriteFile(hFile, szReadBuffer, BUFFER_SIZE, &dWrite, NULL);if (!bWriteSuccessed){unzCloseCurrentFile(unzfile);CloseHandle(hFile);break;}}}free(szReadBuffer);}unzGoToNextFile(unzfile);}if (pFileInfo){delete pFileInfo;pFileInfo = NULL;}if (pGlobalInfo){delete pGlobalInfo;pGlobalInfo = NULL;}//关闭if (unzfile){unzClose(unzfile);}std::cout << "End unpacking the package... " << endl;return true;
}std::string& CZlibHelper::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);elsebreak;}return str;
}//创建多级目录
bool CZlibHelper::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 < (int)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++){//CreateDirectory 创建一个新目录//第一个参数值为文件夹名称,第二个参数值为安全属性,一般设置为NULL即可。//如果正确创建,返回值为1,如果没有正常创建文件夹,则返回0。bSuccess = CreateDirectoryA(vIter->c_str(), NULL) ? true : false;}return bSuccess;
}
用法测试
#include "stdafx.h"
#include <iostream>
#include <string>
#include "zlibHelper.h"int _tmain(int argc, _TCHAR* argv[])
{
#if 1std::string dirpath = "C:\\Users\\Administrator\\Desktop\\zlib"; //源文件/文件夹std::string zipfileName = "C:\\Users\\Administrator\\Desktop\\zlib1.zip"; //目的压缩包//CZlibHelper::CreateZipfromDir(dirpath, zipfileName, "zlib2");CZlibHelper::CreateZipfromDir(dirpath, zipfileName, "");
#endifstd::string srcFilePath = "C:\\Users\\Administrator\\Desktop\\zlib1.zip";std::string tempdir = "C:\\Users\\Administrator\\Desktop\\zlib2";CZlibHelper::UnzipFile(srcFilePath, tempdir);system("pause");return 0;
}
C++ 使用zlib开源库的minizip解压缩文件及文件夹相关推荐
- C++ 压缩文件及文件夹 使用zlib开源库
C++ 压缩文件及文件夹 使用zlib开源库 使用zlib-1.2.11版本的开源库,实现我需要的对文件或者文件夹的压缩,查阅了一些博客大牛的资料,后面根据自己的需要修改.下面给出我的代码: #inc ...
- 使用minizip解压缩多个文件(基于zlib)
写作目的:之前在网上看到很多人在寻找可以解压缩多个文件的程序,其中有尝试zlib的,使用zlib的源码可以生成后缀为点gz的压缩文件,但是一次只能压缩一个文件,无法压缩多个文件.其实,zlib的源码包 ...
- 利用python开源库制作并验证torrent种子文件
下面的文章来源于参考文献[1], 这里将我的实践过程记录如下,方便后来人参考,我的操作系统是Ubuntu 14.04 64bit 一.安装开源BT种子制作软件包 cd /home/taoyx/下载/ ...
- 使用libcurl开源库和Duilib做的下载文件并显示进度条的小工具
转载:http://blog.csdn.net/mfcing/article/details/43603525 转载:http://blog.csdn.net/infoworld/article/de ...
- 【转】DCMTK开源库的学习笔记4:利用ini配置文件对dcm影像进行归档
转自:https://blog.csdn.net/zssureqh/article/details/8846337 背景介绍: 医学影像PACS工作站的服务端需要对大量的dcm文件进行归档,写入数据库 ...
- 【转】DCMTK开源库的学习笔记3:dcmtk文件中数据元的修改
转自:https://blog.csdn.net/zssureqh/article/details/8804736 dcm文件是医学领域DICOM3.0标准所对应的主要的文件格式.前两篇学习笔记中,学 ...
- 再见JCenter,将你的开源库发布到MavenCentral上吧
本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每个工作日都有文章更新. 关于JCenter废弃这件事情,相信许多朋友早就已经知道了.我在几个月前也专门写过一篇文章分 ...
- 常用C/C++开源库
1. 框架 Apache C++ Standard Library : 是一系列算法,容器,迭代器和其他基本组件的集合 ASL : Adobe源代码库提供了同行的评审和可移植的C++源代码库. Boo ...
- C++开源库大全(转)
http://blog.csdn.net/chen19870707/article/details/40427645 程序员要站在巨人的肩膀上,C++拥有丰富的开源库,这里包括:标准库.Web应用框架 ...
最新文章
- 封装一个类搞定90%安卓客户端与服务器端交互
- 自欺欺人的使用 NSTimer 销毁
- Chocolates
- 企业的核心竞争力是什么
- php date( ymd_PHP-date(),time()函数的应用
- 通用权限管理系统组件 (GPM - General Permissions Manager) 中集成多系统的统一登录(数据库源码级)附源码...
- PHP 修改配置文件后重启命名
- Kotlin Weekly 中文周报 —— 16
- Web前端开发规范文档(转)
- struts的体系结构
- docker搭建LDAP统一用户认证
- 玉米社:短视频脚本是什么意思?包含哪些内容?
- 兑吧开发规范《源Java手册》
- 倾斜摄影——三维建模软件ContextCapture (简体中文版安装教程-附软件下载)
- canvas 烟花特效
- Synergy问题收录
- mysql Prepared Statements
- 关于VB中的 comct132.ocx问题!
- 伯克利文理学院的计算机课程,2020年秋季加州大学伯克利分校文理学院学分项目选拔通知...
- c语言托儿所收2到6岁儿童,2018下教师资格考试测试试题:幼儿《保教知识与能力》(三)...
热门文章
- Typora免费版下载安装(小白必看)
- 《〈红楼梦〉通识》:沉醉梦中,是为了醒来
- three.js走进WebVR世界(二)之VREffect.js与VRControls.js
- Office课后总结
- Cyclodextrin-PEG-Cellobiose 、Lentinan、starch ,CD环糊精修饰多糖
- [WEB]php特性
- 数字图像学习4(图像的浮雕效果)
- MATLAB 曲线拟合应用实例
- 1篇文章看懂峰值带宽、流量、转码、连麦、截图五大直播计费方式
- 【代码阅读】PL-VIO