首先 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解压缩文件及文件夹相关推荐

  1. C++ 压缩文件及文件夹 使用zlib开源库

    C++ 压缩文件及文件夹 使用zlib开源库 使用zlib-1.2.11版本的开源库,实现我需要的对文件或者文件夹的压缩,查阅了一些博客大牛的资料,后面根据自己的需要修改.下面给出我的代码: #inc ...

  2. 使用minizip解压缩多个文件(基于zlib)

    写作目的:之前在网上看到很多人在寻找可以解压缩多个文件的程序,其中有尝试zlib的,使用zlib的源码可以生成后缀为点gz的压缩文件,但是一次只能压缩一个文件,无法压缩多个文件.其实,zlib的源码包 ...

  3. 利用python开源库制作并验证torrent种子文件

    下面的文章来源于参考文献[1], 这里将我的实践过程记录如下,方便后来人参考,我的操作系统是Ubuntu 14.04 64bit 一.安装开源BT种子制作软件包 cd  /home/taoyx/下载/ ...

  4. 使用libcurl开源库和Duilib做的下载文件并显示进度条的小工具

    转载:http://blog.csdn.net/mfcing/article/details/43603525 转载:http://blog.csdn.net/infoworld/article/de ...

  5. 【转】DCMTK开源库的学习笔记4:利用ini配置文件对dcm影像进行归档

    转自:https://blog.csdn.net/zssureqh/article/details/8846337 背景介绍: 医学影像PACS工作站的服务端需要对大量的dcm文件进行归档,写入数据库 ...

  6. 【转】DCMTK开源库的学习笔记3:dcmtk文件中数据元的修改

    转自:https://blog.csdn.net/zssureqh/article/details/8804736 dcm文件是医学领域DICOM3.0标准所对应的主要的文件格式.前两篇学习笔记中,学 ...

  7. 再见JCenter,将你的开源库发布到MavenCentral上吧

    本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每个工作日都有文章更新. 关于JCenter废弃这件事情,相信许多朋友早就已经知道了.我在几个月前也专门写过一篇文章分 ...

  8. 常用C/C++开源库

    1. 框架 Apache C++ Standard Library : 是一系列算法,容器,迭代器和其他基本组件的集合 ASL : Adobe源代码库提供了同行的评审和可移植的C++源代码库. Boo ...

  9. C++开源库大全(转)

    http://blog.csdn.net/chen19870707/article/details/40427645 程序员要站在巨人的肩膀上,C++拥有丰富的开源库,这里包括:标准库.Web应用框架 ...

最新文章

  1. 封装一个类搞定90%安卓客户端与服务器端交互
  2. 自欺欺人的使用 NSTimer 销毁
  3. Chocolates
  4. 企业的核心竞争力是什么
  5. php date( ymd_PHP-date(),time()函数的应用
  6. 通用权限管理系统组件 (GPM - General Permissions Manager) 中集成多系统的统一登录(数据库源码级)附源码...
  7. PHP 修改配置文件后重启命名
  8. Kotlin Weekly 中文周报 —— 16
  9. Web前端开发规范文档(转)
  10. struts的体系结构
  11. docker搭建LDAP统一用户认证
  12. 玉米社:短视频脚本是什么意思?包含哪些内容?
  13. 兑吧开发规范《源Java手册》
  14. 倾斜摄影——三维建模软件ContextCapture (简体中文版安装教程-附软件下载)
  15. canvas 烟花特效
  16. Synergy问题收录
  17. mysql Prepared Statements
  18. 关于VB中的 comct132.ocx问题!
  19. 伯克利文理学院的计算机课程,2020年秋季加州大学伯克利分校文理学院学分项目选拔通知...
  20. c语言托儿所收2到6岁儿童,2018下教师资格考试测试试题:幼儿《保教知识与能力》(三)...

热门文章

  1. Typora免费版下载安装(小白必看)
  2. 《〈红楼梦〉通识》:沉醉梦中,是为了醒来
  3. three.js走进WebVR世界(二)之VREffect.js与VRControls.js
  4. Office课后总结
  5. Cyclodextrin-PEG-Cellobiose 、Lentinan、starch ,CD环糊精修饰多糖
  6. [WEB]php特性
  7. 数字图像学习4(图像的浮雕效果)
  8. MATLAB 曲线拟合应用实例
  9. 1篇文章看懂峰值带宽、流量、转码、连麦、截图五大直播计费方式
  10. 【代码阅读】PL-VIO