目录
1.error C2065: “HZIP”: 未声明的标识符
2.error C4996: 'strcpy': This function or variable may be unsafe
网上很多关于压缩的封装类,但要么使用MFC环境,要么版本太老编译之后报错,能够直接使用的很少,我基于Zip Utils和一些前辈的代码简单封装了一个压缩解压文件类,使用VS2017、WIN32环境,简单易用,并给大家减轻一点负担。
1.Zip Utils的介绍
Zip Utils是一个干净、优雅、简单的基于C++/WIN32的压缩工具包。
干净的封装:如果需要压缩文件,可以将zip.cpp和zip.h这两个文件添加到项目中;如果你想要解压缩文件,可以将unzip.cpp, unzip.h添加到项目里。不需要添加额外的库或dll。
······更详细的介绍查看Zip Utils官方文档
文件的下载Zip Utils的资源文件
2.Zip Utils的使用注意事项
Zip Utils官方文档详细介绍的Zip Utils的使用方法并提供了Example,我这里就不再赘述,主要介绍一下将Zip Utils引用VS工程时遇到的问题,并提供解决方法。
1.error C2065: “HZIP”: 未声明的标识符
当直接将"zip.h"、 "unzip.h"引用工程中,会出现错误

主要由于"zip.h"、 "unzip.h"中有一些windows的宏定义未定义,导致头文件无法编译通过,所以在引入"zip.h"、 "unzip.h"之前,必须先包含<Windows.h>

2.error C4996: 'strcpy': This function or variable may be unsafe

由于Zip Utils版本比较老了,有些函数过时了,要编译通过,可在项目—>属性—>C/C++—>命令行—>其他选项中输入/D _CRT_SECURE_NO_WARNINGS

3.错误使用UNICODE
由于在Zip Utils官方文档中说Zip Utils中介绍他使用了TCHAR*,所以兼容Unicode文件名,为了使用wstring,我在预处理器中定义了UNICODE。

产生了编译\LNK错误,是由于宏定义产生了冲突,导致不知道使用char*还是wchar*,详细解释可参考冲突的Unicode定义

所以最终不定义Unicode,而在封装类中不使用wstring而只使用string,幸好也能成功压缩解压文件并使用中文路径依旧正确
3.DZipper的具体实现
1.DZipper.h
/**
* @version Copyright (c) 2022 LLL. Unpublished - All rights reserved
* @file DZipper.h
* @brief ZipUtils的封装类,进行文件的压缩
* @autor dengjinquan
* @date 2023/05/17
*/
#pragma once
//标准库文件
#include<string>
#include<vector>
class DZipper
{
public:
DZipper();
virtual ~DZipper();
//公共函数
public:
/**
* @brief 压缩文件
* @Param[in] strTgt:指定的压缩文件
strSrcFolder:指定的压缩路径
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
bool CompressFolder(std::string strTgt, std::string strSrcFolder);
/**
* @brief 解压缩文件
* @Param[in] strTgt:指定的压缩文件
strSrcFolder:压缩的文件放置的位置
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
bool UnCompressFile(std::string strTgt, std::string strSrcFolder);
/**
* @brief 添加文件到待压缩容器中
* @Param[in] file:完整的路径文件名
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
void AddFile(std::string file);
/**
* @brief 将待压缩容器_compressFileNames中的文件进行压缩
* @Param[in] strTgt:存储的文件名
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
bool CompressFiles(std::string strTgt);
//私有函数
private:
/**
* @brief 判断指定的文件夹是否存在
* @Param[in] strPath:文件夹路径
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
bool _IsFolderExist(std::string& strPath);
/**
* @brief 判断指定的文件是否存在
* @Param[in] strPath:文件路径
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
bool _IsFileExist(std::string strPath);
/**
* @brief 遍历文件夹
* @Param[in] strFile:遍历的文件夹(此方法会主动向路径末尾添加*.*)
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
void _BrowseFile(std::string &strFile);
/**
* @brief 从一个完整的路径名中获取最后的文件名
* @Param[in] pFullPath: 当前文件的完整路径
pSubString: 文件名
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
void _GetFileName(std::string& pFullPath, std::string& pSubString);
/**
* @brief 创建多级目录
* @Param[in] direct: 路径字符串
* @Param[out]
* @exception
* @return
* @author dengjinquan
* @date 2023/05/17
*/
bool _CreatedMultipleDirectory(char* direct);
//私有变量
private:
//待压缩的文件名
std::vector<std::string> _compressFileNames;
};
2.DZipper.cpp
//本工程头文件
#include "Stdafx.h"
#include "DZipper.h"
//标准库
#include<Windows.h> //需要先包含<Windows.h>,zip.h和unzip.h中的一些定义才可被标识,如HZIP
//第三方库
#include "zip.h"
#include "unzip.h"
using namespace std;
DZipper::DZipper()
{
}
DZipper::~DZipper()
{
}
bool DZipper::CompressFolder(std::string strTgt, std::string strSrcFolder)
{
//清空压缩的文件
_compressFileNames.clear();
if (!_IsFolderExist(strSrcFolder))
{
//需要被压缩的文件夹不存在
return false;
}
//压缩解压句柄
HZIP hz;
//创建压缩文件
hz = CreateZip(strTgt.c_str(), 0);
//遍历压缩文件夹
_BrowseFile(strSrcFolder);
for (auto fileName : _compressFileNames)
{
string subFileName;
_GetFileName(fileName, subFileName);
ZipAdd(hz, subFileName.c_str(), fileName.c_str());
}
CloseZip(hz);
return true;
}
bool DZipper::UnCompressFile(std::string strTgt, std::string strSrcFolder)
{
if (strTgt.empty() || strSrcFolder.empty())
{
return false;
}
//如果解压缩的路径不存在 试图创建它
if (!_IsFolderExist(strSrcFolder))
{
//解压后存放的文件夹不存在,则创建它
char* temp = (char*)strSrcFolder.c_str();
if (false == _CreatedMultipleDirectory(temp))
{
//创建目录失败
return false;
}
}
//创建ZIP相关变量
//Zip文件句柄
HZIP hz= OpenZip(strTgt.c_str(), 0);
//操作返回值
ZRESULT zr;
//Zip文件入口
ZIPENTRY ze;
if (hz == 0)
{
//打开Zip文件失败
return false;
}
zr = SetUnzipBaseDir(hz, strSrcFolder.c_str());
if (zr != ZR_OK)
{
//打开Zip文件失败
CloseZip(hz);
return false;
}
zr = GetZipItem(hz, -1, &ze);
if (zr != ZR_OK)
{
//获取Zip文件内容失败
CloseZip(hz);
return false;
}
int numitems = ze.index;
for (int i = 0; i < numitems; i++)
{
zr = GetZipItem(hz, i, &ze);
zr = UnzipItem(hz, i, ze.name);
if (i == 100)
{
int x = 1;
}
if (zr != ZR_OK)
{
//获取Zip文件内容失败
CloseZip(hz);
return false;
}
}
CloseZip(hz);
return true;
}
void DZipper::AddFile(std::string file)
{
_compressFileNames.push_back(file);
}
bool DZipper::CompressFiles(std::string strTgt)
{
//压缩解压句柄
HZIP hz;
//创建压缩文件
hz = CreateZip(strTgt.c_str(), 0);
for (auto fileName : _compressFileNames)
{
//如果文件存在,则压缩进文件中
if (_IsFileExist(fileName))
{
string subFileName;
_GetFileName(fileName, subFileName);
ZipAdd(hz, subFileName.c_str(), fileName.c_str());
}
else
{
CloseZip(hz);
//删除压缩文件
DeleteFile(strTgt.c_str());
return false;
}
}
CloseZip(hz);
return true;
}
bool DZipper::_IsFolderExist(std::string & strPath)
{
std::string sCheckPath = strPath;
if (strPath[strPath.length()-1] != '\\')
sCheckPath += '\\';
sCheckPath += "*.*";
WIN32_FIND_DATA wfd;
BOOL rValue = false;
HANDLE hFind = FindFirstFile(sCheckPath.c_str(), &wfd);
if ((hFind != INVALID_HANDLE_VALUE) &&
(wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) || (wfd.dwFileAttributes&FILE_ATTRIBUTE_ARCHIVE))
{
//如果存在并类型是文件夹
rValue = true;
}
FindClose(hFind);
return rValue;
}
bool DZipper::_IsFileExist(std::string strPath)
{
//获取文件属性
DWORD dwAttrib = GetFileAttributes(strPath.c_str());
//如果文件存在同时不为文件夹,则认为是文件
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
void DZipper::_BrowseFile(std::string & strFile)
{
WIN32_FIND_DATA findData;
std::string strFindFile = strFile + "\\*";
HANDLE hFind = FindFirstFile(strFindFile.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
{
//文件夹不存在
return;
}
do
{
if (std::string(findData.cFileName).compare(".") == 0 ||
std::string(findData.cFileName).compare("..") == 0)continue;
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
//如果是目录
std::string strDir1 = strFile + "\\";
strDir1.append(std::string(findData.cFileName).c_str());
_BrowseFile(strDir1);
}
else
{
_compressFileNames.push_back(strFile + "\\" + std::string(findData.cFileName));
}
} while (FindNextFile(hFind, &findData));
return;
}
void DZipper::_GetFileName(std::string & pFullPath, std::string & pSubString)
{
//rfind:从字串从右往左数第一个字符的位置,但返回的值是从左往右算
pSubString = pFullPath.substr(pFullPath.rfind('\\')+1, pFullPath.length()-1);
}
bool DZipper::_CreatedMultipleDirectory(char * direct)
{
std::string Directoryname = direct;
//如果Directoryname后面不是'\\',添加'\\'
if (Directoryname[Directoryname.length() - 1] != '\\')
{
//append(n,str):添加n个str
Directoryname.append(1, '\\');
}
std::vector< std::string> vpath;
std::string strtemp;
bool bSuccess = false;
for (int i = 0; i < Directoryname.length(); i++)
{
if (Directoryname[i] != '\\')
{
strtemp.append(1, Directoryname[i]);
}
else
{
vpath.push_back(strtemp);
strtemp.append(1, '\\');
}
}
vector< std::string>::const_iterator vIter = vpath.begin();
for (vIter; vIter != vpath.end(); vIter++)
{
bSuccess = CreateDirectory((LPCTSTR)vIter->c_str(), NULL) ? TRUE : FALSE;
}
return bSuccess;
}
3.demo
//本工程头文件
#include "DZipper.h"
int main()
{
//Example1
//压缩文件夹压缩、解压到指定文件夹
DZipper dzip;
bool a=dzip.CompressFolder("C:\\Users\\mufish\\Desktop\\test1.zip", "C:\\Users\\mufish\\Desktop\\aaa");
bool b=dzip.UnCompressFile("C:\\Users\\mufish\\Desktop\\test1.zip", "C:\\Users\\mufish\\Desktop\\你好");
//Example2
//添加文件并压缩,解压到指定文件夹
dzip.AddFile("C:\\Users\\mufish\\Desktop\\aaa\\111.txt");
dzip.AddFile("C:\\Users\\mufish\\Desktop\\aaa\\222.txt");
dzip.AddFile("C:\\Users\\mufish\\Desktop\\aaa\\333.txt");
bool c= dzip.CompressFiles("C:\\Users\\mufish\\Desktop\\test2.zip");
bool d= dzip.UnCompressFile("C:\\Users\\mufish\\Desktop\\test2.zip", "C:\\Users\\mufish\\Desktop\\世界");
return 0;
}
4.总结
该封装类有两种压缩模式,一种解压模式,支持中文路径,如果在使用过程中有什么问题,可以反馈,我尽量修改。
文章介绍了DZipper,一个基于ZipUtils和前辈代码封装的C++压缩解压文件类,适用于VS2017和WIN32环境。DZipper解决了ZipUtils在VS工程中引用时可能出现的编译问题,如未声明的标识符、不安全函数警告以及UNICODE宏定义冲突。类库提供压缩文件夹、解压缩文件、添加文件到压缩容器等功能,支持中文路径。文章还包含示例代码展示如何使用DZipper进行压缩和解压缩操作。
431





