C++压缩文件类:Zip Utils的封装,注释满满

文章介绍了DZipper,一个基于ZipUtils和前辈代码封装的C++压缩解压文件类,适用于VS2017和WIN32环境。DZipper解决了ZipUtils在VS工程中引用时可能出现的编译问题,如未声明的标识符、不安全函数警告以及UNICODE宏定义冲突。类库提供压缩文件夹、解压缩文件、添加文件到压缩容器等功能,支持中文路径。文章还包含示例代码展示如何使用DZipper进行压缩和解压缩操作。

目录

1.Zip Utils的介绍

2.Zip Utils的使用注意事项

1.error C2065: “HZIP”: 未声明的标识符

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

3.错误使用UNICODE

3.DZipper的具体实现

1.DZipper.h

2.DZipper.cpp

3.demo

4.总结


        网上很多关于压缩的封装类,但要么使用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.总结

        该封装类有两种压缩模式,一种解压模式,支持中文路径,如果在使用过程中有什么问题,可以反馈,我尽量修改。

评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值