C++ 使用bit7z实现压缩与解压缩

最近项目有个关于文件压缩与解压缩的需求,网上找了一大圈发现bit7z这个开源库用的比较多,主要是开源免费,而且还比较好用。

网上找了一圈关于压缩和解压缩的代码实现的比较多,但是大部分是不能直接拿来用的,都需要或多或少需要修改一点。我这里就参考了两位博主的代码,在这两位博主的基础上修改了代码,实现通用的C++,只要求C++版本大于等于17,如果是C++11的话需要修改一点关于C++对文件的操作的代码。

至于环境搭建还有如何引用库,可以参考下面参考文章,我这里就主要是贴代码了。上github如果不太方便的话,gitee有镜像可以从gitee下载,这里注意一点,我尝试bit7z版本是3.2版本,这个版本和4.0不太一样。4.0感觉有点新,我尝试了一下,失败了。没有细研究。如果就是简单用的话建议3.2版本的bit7z。

头文件:

#pragma once
#ifndef NIMO_OBS_ZLIB_H
#define NIMO_OBS_ZLIB_H

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
#include <set>
#include <functional>
#include <bit7z.hpp>
#include <bit7zlibrary.hpp>
#include <filesystem>

class ZlibHelper 
{
private:
	uint64_t mSize;
	typedef std::function<void(double process)> UnZipProcessCallback;
	typedef std::function<void(std::string filename)> UnZipFileCallback;
	UnZipProcessCallback upc;
	UnZipFileCallback ufc;
public:
	ZlibHelper();
	~ZlibHelper();

	void Compress(const std::string& Src, const std::string& Dest, const std::string& Password = "");		// 压缩
	void Extract(const std::string& Src, const std::string& Dest, const std::string& Password = "");		// 解压
	void SetUnZipProcessCallback(UnZipProcessCallback upc);
	void SetUnZipFileCallback(UnZipFileCallback ufc);
private:
	void GetSizeOfZipPackage(const std::string& Src);
	void ProcessCallback(uint64_t size);
	void FileCallback(std::wstring filename);
	std::wstring toWstring(const std::string& input);
	std::string toString(const std::wstring& input);
};






#endif

源文件

#include "ZipHelper.h"

ZlibHelper::ZlibHelper(){}

ZlibHelper::~ZlibHelper(){}

// 压缩
void ZlibHelper::Compress(const std::string& Src, const std::string& Dest, const std::string& Password)
{
	std::string::size_type iPos = (Dest.find_last_of('\\') + 1) == 0 ? Dest.find_last_of('/') + 1 : Dest.find_last_of('\\') + 1;
	std::filesystem::path filePath = Dest.substr(0, iPos);	// 获取文件路径
	std::string fileSuffix = Dest.substr(Dest.rfind(".") + 1, Dest.size());	// 获取文件类型
	bit7z::Bit7zLibrary lib(L"7z.dll");
	std::shared_ptr<bit7z::BitCompressor> m_pCompressor = nullptr;	
	if (fileSuffix == "7z")
	{
		m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, bit7z::BitFormat::SevenZip);
	}
	else if (fileSuffix == "zip")
	{
		m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, bit7z::BitFormat::Zip);
	}
	else if (fileSuffix == "bz2")
	{
		m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, bit7z::BitFormat::BZip2);
	}
	else if (fileSuffix == "xz")
	{
		m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, bit7z::BitFormat::Xz);
	}
	else if (fileSuffix == "wim")
	{
		m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, bit7z::BitFormat::Wim);
	}
	else if (fileSuffix == "tar")
	{
		m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, bit7z::BitFormat::Tar);
	}
	else if (fileSuffix == "gz")
	{
		m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, bit7z::BitFormat::GZip);
	}
	else
	{
		m_pCompressor = nullptr;
		return;
	}
	
	try {
		// 检查是否存在这个文件夹,不存在新建
		create_directories(filePath); // c++ 17 起
		bit7z::ProgressCallback pc = std::bind(&ZlibHelper::ProcessCallback, this, std::placeholders::_1);
		bit7z::FileCallback fc = std::bind(&ZlibHelper::FileCallback, this, std::placeholders::_1);
		m_pCompressor->setProgressCallback(pc);
		m_pCompressor->setFileCallback(fc);
		std::wstring msSourcePath = toWstring(Src);
		std::wstring msDestDir = toWstring(Dest);
		std::wstring msPassword = toWstring(Password);
		m_pCompressor->setPassword(msPassword);
		m_pCompressor->compressDirectory(msSourcePath, msDestDir);
		m_pCompressor->setUpdateMode(true);
	}
	catch (const bit7z::BitException& ex) {
		std::cout << ex.what() << std::endl;
	}
}

// 获取Zip包的大小
void ZlibHelper::GetSizeOfZipPackage(const std::string& Src)
{
	std::wstring src = toWstring(Src);
	bit7z::Bit7zLibrary lib(L"7z.dll");
	bit7z::BitArchiveInfo info(lib, src, bit7z::BitFormat::SevenZip);
	mSize = info.size();
}

void ZlibHelper::ProcessCallback(uint64_t size)
{
	double process = ((1.0 * size) / mSize);
	//std::wcout << process << "%" << std::endl;
	if (upc) {
		upc(process);
	}
}

void ZlibHelper::FileCallback(std::wstring filename)
{
	std::string temp = toString(filename);
	//std::cout << temp.c_str() << std::endl;
	if (ufc) {
		ufc(temp);
	}
}

// 解压
void ZlibHelper::Extract(const std::string& Src, const std::string& Dest, const std::string& Password)
{
	std::string fileSuffix = Src.substr(Src.rfind(".") + 1, Src.size());
	bit7z::Bit7zLibrary lib(L"7z.dll");
	std::shared_ptr<bit7z::BitExtractor> m_pExtractor = nullptr;
	// 检查是否存在这个文件夹,不存在新建
	create_directories(std::filesystem::path(Dest)); // c++ 17 起
	if (fileSuffix == "7z")
	{
		//后缀L".7z"
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::SevenZip);
	}
	else if (fileSuffix == "zip")
	{
		//后缀L".zip"
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::Zip);
	}
	else if (fileSuffix == "rar")
	{
		//后缀L".rar"
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::Rar5);
	}
	else if (fileSuffix == "bz2")
	{
		//后缀L".bz2
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::BZip2);
	}
	else if (fileSuffix == "xz")
	{
		//后缀L".xz
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::Xz);
	}
	else if (fileSuffix == "wim")
	{
		//后缀L".wim
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::Wim);
	}
	else if (fileSuffix == "tar")
	{
		//后缀L".tar
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::Tar);
	}
	else if (fileSuffix == "gz")
	{
		//后缀L".gz
		m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, bit7z::BitFormat::GZip);
	}
	else
	{
		m_pExtractor = nullptr;
		return;
	}
	
	try {
		bit7z::ProgressCallback pc = std::bind(&ZlibHelper::ProcessCallback, this, std::placeholders::_1);
		bit7z::FileCallback fc = std::bind(&ZlibHelper::FileCallback, this, std::placeholders::_1);
		m_pExtractor->setProgressCallback(pc);
		m_pExtractor->setFileCallback(fc);
		std::wstring msSourcePath = toWstring(Src);
		std::wstring msDestDir = toWstring(Dest);
		std::wstring msPassword = toWstring(Password);
		m_pExtractor->setPassword(msPassword);
		m_pExtractor->extract(msSourcePath, msDestDir);
	}
	catch (const bit7z::BitException& ex) {
		std::cout << ex.what() << std::endl;
	}
}

void ZlibHelper::SetUnZipProcessCallback(UnZipProcessCallback upc)
{
	this->upc = upc;
}

void ZlibHelper::SetUnZipFileCallback(UnZipFileCallback ufc)
{
	this->ufc = ufc;
}

//convert string to wstring
std::wstring ZlibHelper::toWstring(const std::string& input)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	return converter.from_bytes(input);
}

//convert wstring to string 
std::string ZlibHelper::toString(const std::wstring& input)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	return converter.to_bytes(input);
}

测试代码:

#include "ZipHelper.h"

int main()
{
	//std::string src = "F:/code/console/Use7z/data/qwe/asd/zxc/123.7z";
	std::string src = "F:/code/console/Use7z/data/123.7z";
	std::string dist = "F:\\code\\console\\Use7z\\data\\out\\asd\\zxc\\123\\";
	ZlibHelper* pUnzip = new ZlibHelper();
	pUnzip->Extract(src, dist);
	//pUnzip->Compress(dist, src);
	return 0;
}

我自己写的demo资源。 

 use7z的demo,里面主要简单封装了一个压缩和解压缩的函数资源-CSDN文库

--------------20231008-------------------------------

基于上面函数我修改了一点

头文件

#pragma once
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
#include <set>
#include <functional>
#include <bit7z.hpp>
#include <bit7zlibrary.hpp>
#include <filesystem>

#if _MSC_VER >= 1910
using Path = std::filesystem::path;
using DirIter = std::filesystem::directory_iterator;
#elif _MSC_VER >= 1900
using Path = std::tr2::sys::path;
using DirIter = std::tr2::sys::directory_iterator;
#endif

class ZlibHelper
{
private:
	uint64_t mSize;
	typedef std::function<void(double process)> UnZipProcessCallback;
	typedef std::function<void(std::string filename)> UnZipFileCallback;
	UnZipProcessCallback upc;
	UnZipFileCallback ufc;
public:
	ZlibHelper();
	~ZlibHelper();

	void Compress(const std::string& Src, const std::string& Dest, bool IsdeleteSourceFile = false, const std::string& Password = "");		// 压缩
	void Extract(const std::string& Src, const std::string& Dest, bool IsdeleteSourceFile = false, const std::string& Password = "");		// 解压
	void SetUnZipProcessCallback(UnZipProcessCallback upc);
	void SetUnZipFileCallback(UnZipFileCallback ufc);
private:
	void test();  // 使用 ZlibHelper demo
	uint64_t GetSizeOfFolder(const std::string& src);	// 获得字节数
	void GetSizeOfZipPackage(const std::string& Src);
	void ProcessCallback(uint64_t size);
	void FileCallback(std::wstring filename);
	std::wstring toWstring(const std::string& input);
	std::string toString(const std::wstring& input);

private:
	bool m_bIsdeleteSourceFile = false;
	std::string m_CompressFolderPath = "";
	std::map<std::string, bit7z::BitInOutFormat*> m_ZlibFormat;
};

源文件:

#include "ZlibHelper.h"


ZlibHelper::ZlibHelper() 
{
	m_ZlibFormat["7z"]	= const_cast<bit7z::BitInOutFormat*>(&bit7z::BitFormat::SevenZip);
	m_ZlibFormat["zip"] = const_cast<bit7z::BitInOutFormat*>(&bit7z::BitFormat::Zip);
	m_ZlibFormat["bz2"] = const_cast<bit7z::BitInOutFormat*>(&bit7z::BitFormat::BZip2);
	m_ZlibFormat["xz"]	= const_cast<bit7z::BitInOutFormat*>(&bit7z::BitFormat::Xz);
	m_ZlibFormat["wim"] = const_cast<bit7z::BitInOutFormat*>(&bit7z::BitFormat::Wim);
	m_ZlibFormat["tar"] = const_cast<bit7z::BitInOutFormat*>(&bit7z::BitFormat::Tar);
	m_ZlibFormat["gz"]	= const_cast<bit7z::BitInOutFormat*>(&bit7z::BitFormat::GZip);
}

ZlibHelper::~ZlibHelper() {}

// 压缩
void ZlibHelper::Compress(const std::string& Src, const std::string& Dest, bool IsdeleteSourceFile, const std::string& Password)
{	
	m_CompressFolderPath = Src;
	m_bIsdeleteSourceFile = IsdeleteSourceFile;
	mSize = GetSizeOfFolder(m_CompressFolderPath);
	std::string::size_type iPos = (Dest.find_last_of('\\') + 1) == 0 ? Dest.find_last_of('/') + 1 : Dest.find_last_of('\\') + 1;
	Path filePath = Dest.substr(0, iPos);	// C++ 11 获取文件路径
	std::string fileSuffix = Dest.substr(Dest.rfind(".") + 1, Dest.size());	// 获取文件类型
	bit7z::Bit7zLibrary lib(L"7z.dll");
	try {
		std::shared_ptr<bit7z::BitCompressor> m_pCompressor = std::make_shared<bit7z::BitCompressor>(lib, *(m_ZlibFormat[fileSuffix]));
		create_directories(filePath);  // 检查是否存在这个文件夹,不存在新建
		bit7z::ProgressCallback pc = std::bind(&ZlibHelper::ProcessCallback, this, std::placeholders::_1);
		bit7z::FileCallback fc = std::bind(&ZlibHelper::FileCallback, this, std::placeholders::_1);
		m_pCompressor->setProgressCallback(pc);
		m_pCompressor->setFileCallback(fc);
		std::wstring msSourcePath = toWstring(Src);
		std::wstring msDestDir = toWstring(Dest);
		std::wstring msPassword = toWstring(Password);
		m_pCompressor->setPassword(msPassword);
		m_pCompressor->compressDirectory(msSourcePath, msDestDir);
		m_pCompressor->setUpdateMode(true);		
	}
	catch (const bit7z::BitException& ex) {
		std::cout << ex.what() << std::endl;
	}
}

// 解压
void ZlibHelper::Extract(const std::string& Src, const std::string& Dest, bool IsdeleteSourceFile, const std::string& Password)
{
	m_bIsdeleteSourceFile = IsdeleteSourceFile;
	std::string fileSuffix = Src.substr(Src.rfind(".") + 1, Src.size());
	bit7z::Bit7zLibrary lib(L"7z.dll");
	// 检查是否存在这个文件夹,不存在新建
	create_directories(Path(Dest)); // c++ 11
	try 
	{
		std::shared_ptr<bit7z::BitExtractor> m_pExtractor = std::make_shared<bit7z::BitExtractor>(lib, *(m_ZlibFormat[fileSuffix]));
		bit7z::ProgressCallback pc = std::bind(&ZlibHelper::ProcessCallback, this, std::placeholders::_1);
		bit7z::FileCallback fc = std::bind(&ZlibHelper::FileCallback, this, std::placeholders::_1);
		m_pExtractor->setProgressCallback(pc);
		m_pExtractor->setFileCallback(fc);
		std::wstring msSourcePath = toWstring(Src);
		std::wstring msDestDir = toWstring(Dest);
		std::wstring msPassword = toWstring(Password);
		m_pExtractor->setPassword(msPassword);
		m_pExtractor->extract(msSourcePath, msDestDir);
	}
	catch (const bit7z::BitException& ex) {
		std::cout << ex.what() << std::endl;
	}
}

void ZlibHelper::test()
{
	//std::string src = "F:/code/console/Use7z/data/qwe/asd/zxc/123.7z";
	std::string src = "F:/code/console/Use7z/data/123.7z";
	std::string dist = "F:\\code\\console\\Use7z\\data\\out\\asd\\zxc\\123\\";
	ZlibHelper* pUnzip = new ZlibHelper();
	pUnzip->Extract(src, dist);
	//pUnzip->Compress(dist, src);
}

uint64_t ZlibHelper::GetSizeOfFolder(const std::string& src)
{

	uint64_t lFolderSize = 0;
	Path src_dir(src);
	for (DirIter end, ite(src_dir); ite != end; ++ite)
	{
		if (!is_directory(ite->path()))
		{
			lFolderSize += file_size(Path(src + "\\" + ite->path().filename().string()));
		}
	};
	return lFolderSize;
}

// 获取Zip包的大小
void ZlibHelper::GetSizeOfZipPackage(const std::string& Src)
{
	std::wstring src = toWstring(Src);
	bit7z::Bit7zLibrary lib(L"7z.dll");
	bit7z::BitArchiveInfo info(lib, src, bit7z::BitFormat::SevenZip);
	mSize = info.size();
}

void ZlibHelper::ProcessCallback(uint64_t size)
{
	double process = ((100.0 * size) / mSize);
	if (upc) {
		upc(process);
	}
	if (process == 100 && m_bIsdeleteSourceFile)	// 压缩完删除源文件
	{
		remove_all(Path(m_CompressFolderPath));	
	}
}

void ZlibHelper::FileCallback(std::wstring filename)
{
	std::string temp = toString(filename);
	//std::cout << temp.c_str() << std::endl;
	if (ufc) {
		ufc(temp);
	}
}


void ZlibHelper::SetUnZipProcessCallback(UnZipProcessCallback upc)
{
	this->upc = upc;
}

void ZlibHelper::SetUnZipFileCallback(UnZipFileCallback ufc)
{
	this->ufc = ufc;
}

//convert string to wstring
std::wstring ZlibHelper::toWstring(const std::string& input)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	return converter.from_bytes(input);
}

//convert wstring to string 
std::string ZlibHelper::toString(const std::wstring& input)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	return converter.to_bytes(input);
}

参考文章:

C++解压库bit7z编译以及使用-CSDN博客

C++ 调用7z进行解压缩,并返回解压缩进度和异常信息_7z.dll调用-CSDN博客

C++ string获取文件路径文件名、文件路径、文件后缀(两种方式)_string 路径-CSDN博客

std::filesystem::create_directory, std::filesystem::create_directories - C++中文 - API参考文档 (apiref.com) C++11文件目录操作简介_c++ 目录操作-CSDN博客

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
哈夫曼树是一种有效的数据压缩算法,可以通过构建哈夫曼树来实现文件的压缩压缩。 哈夫曼树的构建过程主要分为两步:统计字符频率和构建哈夫曼树。 首先,在压缩文件之前,需要统计每个字符在文件中出现的频率。可以遍历文件中的每个字符,使用一个哈希表来记录每个字符出现的频率。 然后,根据字符的频率构建哈夫曼树。先将每个字符及其频率作为一个节点插入优先队列(最小堆),按照频率进行排序。接下来,从优先队列中取出频率最小的两个节点作为左右子节点,新建一个父节点,将两个子节点连接到父节点上,并将父节点重新插入优先队列。重复这个过程,直到队列中只剩下一个节点,即构建出哈夫曼树。 完成哈夫曼树的构建后,可以通过遍历哈夫曼树的路径来生成每个字符的编码。从根节点开始,左子节点表示0,右子节点表示1,递归地沿着树的路径进行编码。将每个字符及其对应的编码存入编码表中。 在压缩文件时,可以使用编码表将文件中的字符逐个替换为对应的编码,从而将文件压缩为较小的二进制文件。在压缩时,根据编码表将编码逐个转换回原始字符,恢复原始文件。 哈夫曼树算法能够根据字符频率生成可变长度的编码,使得出现频率高的字符使用更短的编码,提高压缩效率。通过哈夫曼树实现的文件压缩压缩可以有效地减小文件的大小,方便存储和传输。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

波雅_汉库克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值