项目优化中文件压缩

需求背景:

        在停车收费项目中,一些车流量大的车厂日志信息文件增加的很快,虽然采用spdlog根据大小限制了每一份日志的大小,但是往往这种车流量大的车厂是一些大型商场,各种类型车辆收费不同,不同时间往往有不同的优惠,且跟车严重会带来不少各种各样的问题;日志需要保存的时间就更久一些,因此对于日志按照时间尺度进行打包压缩是一个很好的方案;此外对于软件升级工具一般需要对现场数据库数据和原版软件备份,防止升级失败影响现场使用,一般数据库数据和软件等较大,也会需要采用压缩备份。目前在数据备份等需要压缩的场景中,在备份线程中使用zlib进行压缩操作。

zlib的使用

zlib基本介绍

        zlib是一个开源的数据压缩库,用于在应用程序中进行数据的压缩和解压缩操作。它提供了一组函数和数据结构,可以实现广泛的压缩算法,其中最常用的是Deflate算法。zlib库的设计简单、高效,并且具有广泛的应用领域。

zlib库的主要特点包括:

  1. 数据压缩和解压缩:zlib库可以将数据压缩为更小的体积,以节省存储空间或网络带宽,并且可以将压缩后的数据解压缩回原始数据。
  2. 高效性能:zlib库的压缩和解压缩算法经过优化,具有较高的压缩速度和解压缩速度。
  3. 可移植性:zlib库是使用纯C编写的,可以在各种操作系统和平台上进行编译和运行。
  4. 简单易用:zlib库提供了简单的API,易于集成到应用程序中,并且具有丰富的文档和示例代码。

        在实际应用中,zlib库常用于压缩文件、网络传输、数据库存储、图像处理等场景。它被广泛应用于各种领域,包括Web服务器、数据压缩工具、游戏开发等。

        除了基本的压缩和解压缩功能,zlib库还提供了一些高级特性,如流式压缩、字典压缩、动态压缩级别调整等,以满足不同场景下的需求。zlib是一个功能强大、高效可靠的数据压缩库,可以帮助开发者在应用程序中实现数据的压缩和解压缩功能,从而提升存储和传输效率。

zlib的编译

下载地址:GitHub - madler/zlib: A massively spiffy yet delicately unobtrusive compression library.

        cmake编译后根据需求生成动态库即可。

        注意事项:需要包含头文件zlib.h和zconf.h,且最好两个头文件在同一个文件夹下;项目包含目录若没有到这两个文件的目录则需要注意修改zlib.h;因为zlib.h包含了zconf.h,需要修改包含目录。

项目中使用

        压缩工具类代码:定义了单例模式便于使用,此外定义压缩和解压接口,具体如下。

#pragma once
#include<string>
#include "zlib.h"

#define zibInstance zlibTool::instance()
class zlibTool
{
public:
	zlibTool() = default;
	~zlibTool() = default;
	static zlibTool* instance();
	zlibTool(const zlibTool&) = delete;
	zlibTool& operator= (const zlibTool&) = delete;
	bool compressFile(std::string&inFilePath, std::string&outFilePath,int method = Z_DEFAULT_COMPRESSION);
	bool unCompressFile(std::string&inFilePath, std::string&outFilePath);
};

压缩工具类代码实现

单例部分代码

zlibTool* zlibTool::instance()
{
	static zlibTool Instance;
	return &Instance;
}

压缩函数代码:

#define CHUNK 16384

bool zlibTool::compressFile(std::string&inFilePath, std::string&outFilePath, int method)
{
	std::ifstream inputFile(inFilePath, std::ios::binary);
	if (!inputFile) {
		cLogger("ISC_UpGrade")->error(QString("打开输入文件%1失败").arg(inFilePath.c_str()).toStdString());
		return false;
	}

	std::ofstream outputFile(outFilePath, std::ios::binary);
	if (!outputFile) {
		cLogger("ISC_UpGrade")->error(QString("打开输出文件%1失败").arg(outFilePath.c_str()).toStdString());
		return false;
	}

	// 设置压缩参数
	z_stream strm;
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;

	// 初始化压缩流
	if (deflateInit(&strm, method) != Z_OK) {
		cLogger("ISC_UpGrade")->error(QString("初始化 deflate stream失败").toStdString());
		return false;
	}

	// 读取输入文件并压缩数据
	const int bufferSize = CHUNK;
	std::vector<char> buffer(bufferSize);
	do {
		inputFile.read(buffer.data(), bufferSize);
		strm.avail_in = static_cast<uInt>(inputFile.gcount());
		strm.next_in = reinterpret_cast<Bytef*>(buffer.data());

		do {
			std::vector<char> outputBuffer(bufferSize);
			strm.avail_out = bufferSize;
			strm.next_out = reinterpret_cast<Bytef*>(outputBuffer.data());

			// 压缩数据
			int result = deflate(&strm, inputFile.eof() ? Z_FINISH : Z_NO_FLUSH);
			if (result == Z_STREAM_ERROR) {
				cLogger("ISC_UpGrade")->error(QString("初始化 deflate stream失败").toStdString());
				deflateEnd(&strm);
				return false;
			}

			// 写入压缩后的数据到输出文件
			std::streamsize compressedSize = bufferSize - strm.avail_out;
			outputFile.write(outputBuffer.data(), compressedSize);
		} while (strm.avail_out == 0);
	} while (!inputFile.eof());

	// 压缩结束
	deflateEnd(&strm);

	inputFile.close();
	outputFile.close();

	return true;
}

解压函数代码:

bool zlibTool::unCompressFile(std::string&inFilePath, std::string&outFilePath)
{
	std::ifstream inputFile(inFilePath, std::ios::binary);
	if (!inputFile) {
		cLogger("ISC_UpGrade")->error(QString("打开输入文件%1失败").arg(inFilePath.c_str()).toStdString());
		return false;
	}

	std::ofstream outputFile(outFilePath, std::ios::binary);
	if (!outputFile) {
		cLogger("ISC_UpGrade")->error(QString("打开输出文件%1失败").arg(outFilePath.c_str()).toStdString());
		return false;
	}

	// 设置解压缩参数
	z_stream strm;
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;
	strm.next_in = Z_NULL;

	// 初始化解压缩流
	if (inflateInit(&strm) != Z_OK) {
		cLogger("ISC_UpGrade")->error(QString("初始化 deflate stream失败").toStdString());
		return false;
	}

	// 读取输入文件并解压缩数据
	const int bufferSize = 16384;
	std::vector<char> buffer(bufferSize);
	do {
		inputFile.read(buffer.data(), bufferSize);
		strm.avail_in = static_cast<uInt>(inputFile.gcount());
		strm.next_in = reinterpret_cast<Bytef*>(buffer.data());

		do {
			std::vector<char> outputBuffer(bufferSize);
			strm.avail_out = bufferSize;
			strm.next_out = reinterpret_cast<Bytef*>(outputBuffer.data());

			// 解压缩数据
			int result = inflate(&strm, inputFile.eof() ? Z_FINISH : Z_NO_FLUSH);
			if (result == Z_STREAM_ERROR) {
				cLogger("ISC_UpGrade")->error(QString("解压缩失败失败").arg(strm.msg).toStdString());
				inflateEnd(&strm);
				return false;
			}

			// 写入解压缩后的数据到输出文件
			std::streamsize uncompressedSize = bufferSize - strm.avail_out;
			outputFile.write(outputBuffer.data(), uncompressedSize);
		} while (strm.avail_out == 0);
	} while (!inputFile.eof());

	// 解压缩结束
	inflateEnd(&strm);
	inputFile.close();
	outputFile.close();
	return true;
}

测试代码:

string  filename = R"(G:\ProjectCode\2024\PmsUpdater\Code\Test.txt)";
	string outFilename = R"(G:\ProjectCode\2024\PmsUpdater\Code\Test.zip)";
	string outFilename2 = R"(G:\ProjectCode\2024\PmsUpdater\Code\Test2.txt)";
	if (zibInstance->compressFile(filename, outFilename))
	{
		zibInstance->unCompressFile(outFilename, outFilename2);
	}

测试结果

QZipReader/QZipWriter类

        Qt私有的压缩工具,需要Qt安装时下载了源码,在Qt项目中可以很方便的使用而不必在编译第三方库。

基本用法

QZipWriter的头文件

#include <QtCore/qstring.h>
#include <QtCore/qfile.h>

QT_BEGIN_NAMESPACE

class QZipWriterPrivate;
class Q_GUI_EXPORT QZipWriter
{
public:
    explicit QZipWriter(const QString &fileName, QIODevice::OpenMode mode = (QIODevice::WriteOnly | QIODevice::Truncate) );

    explicit QZipWriter(QIODevice *device);
    ~QZipWriter();

    QIODevice* device() const;

    bool isWritable() const;
    bool exists() const;

    enum Status {
        NoError,
        FileWriteError,
        FileOpenError,
        FilePermissionsError,
        FileError
    };

    Status status() const;

    enum CompressionPolicy {
        AlwaysCompress,
        NeverCompress,
        AutoCompress
    };

    void setCompressionPolicy(CompressionPolicy policy);//设置压缩策略
    CompressionPolicy compressionPolicy() const;

    void setCreationPermissions(QFile::Permissions permissions);
    QFile::Permissions creationPermissions() const;

    void addFile(const QString &fileName, const QByteArray &data);//添加待压缩的文件数据

    void addFile(const QString &fileName, QIODevice *device);//添加带压缩的文件流

    void addDirectory(const QString &dirName);//添加创建目录,不是压缩

    void addSymLink(const QString &fileName, const QString &destination);

    void close();
private:
    QZipWriterPrivate *d;
    Q_DISABLE_COPY(QZipWriter)
};

QT_END_NAMESPACE

#endif // QT_NO_TEXTODFWRITER
#endif // QZIPWRITER_H
 

 

项目中使用:

文件夹递归压缩代码:

#include"QtGui/private/qzipreader_p.h"
#include"QtGui/private/qzipwriter_p.h"

bool ISC_AsyBackUpObj::backUp2Zip(QZipWriter *zip, const QString &dirPath, const QString &base, const QStringList&ignoreDirLists) {
	QDir dir(dirPath);
	QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
	for (const QFileInfo &entry : entries) {
		QString filePath = entry.absoluteFilePath();
		if (entry.isDir())
		{
			if (!ignoreDirLists.contains(entry.baseName()))
			{
				QString baseDirStr = base.isEmpty() ? entry.fileName() : base + QDir::separator() + entry.fileName();
				if (!backUp2Zip(zip, filePath, baseDirStr))
				{
					cLogger("ISC")->error(TR("文件夹%1压缩备份过程中打开失败").arg(filePath).toStdString().c_str());
					return false;
				}
			}
		}
		else
		{ 
			// 如果是文件,则添加到ZIP
			QFile file(filePath);
			if (!file.open(QIODevice::ReadOnly))
			{
				cLogger("ISC")->error(TR("文件%1压缩备份过程中打开失败").arg(file.fileName()).toStdString().c_str());
				return false;
			}
			else
			{
				QByteArray fileData = file.readAll();
				QString baseName = base.isEmpty() ? entry.fileName() : base + QDir::separator() + entry.fileName();
				zip->addFile(baseName, fileData);
				file.close();	
				m_currentSize += entry.size();
			}
		}
	}
	return true;
}

递归解压代码

bool ISC_AsyBackUpObj::restoreFromZip(const QString&srcZip, const QString&destDir)
{
	//解压
	QZipReader zipReader(srcZip);
	if (!zipReader.exists())
	{
		return false;
	}
	if (!zipReader.status() != QZipReader::Status::NoError)
	{
		return false;
	}
	//解压到目标目录 压缩文件中文件信息齐全可用
	return zipReader.extractAll(destDir);

	/*
	bool read = zipReader.isReadable();
	int count = zipReader.count();
	int Status = zipReader.status();
	QDir().mkpath(destDir);
	foreach(const QZipReader::FileInfo &fileInfo, zipReader.fileInfoList()) 
	{
		QString extractFilePath = QDir(destDir).filePath(fileInfo.filePath);
		if (fileInfo.isDir)
		{
			QDir().mkpath(extractFilePath);
		}
		else
		{
			QFile extractFile(extractFilePath);
			if (!extractFile.open(QIODevice::WriteOnly))
			{
				return false;
			}
			QByteArray data = zipReader.fileData(fileInfo.filePath);
			if (data.isEmpty())
			{
				continue;
			}
			if (extractFile.write(data) == -1)
			{
				return false;
			}
		}
	}
	return true;
	*/
}

7z

7z基本介绍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值