Qt 压缩/解压文件

前面讲了很多Qt的文件操作,文件操作自然就包括压缩与解压缩文件了,正好最近项目里要用到压缩以及解压缩文件,所以就研究了一下Qt如何压缩与解压缩文件。

QZipReader/QZipWriter

QZipReader 和 QZipWriter 类提供了用于读取和写入 ZIP 格式文件的功能,这个是qt自带的,试了一下个人感觉并不好用。

首先QZipReader/QZipWriter是在Qt5.14之后才引入的,而且使用需要用到gui-private这个模块,搜了一下,在 Qt 中,gui-private 模块是 Qt 框架中的一个私有模块,通常不是为公共使用而设计的。该模块包含了一些 Qt GUI 框架内部使用的实现细节、私有接口和工具类,而不是为外部开发者提供的公共 API。一般来说,Qt 将其功能模块划分为公共模块和私有模块。公共模块包含了开发者可以直接使用的公共 API,而私有模块则包含了框架内部的实现细节和工具类,这些类通常不应该被外部开发者直接使用。所以才不推荐使用。直接看代码:

首先pro文件包含对应模块:

QT +=gui-private

头文件包含:

#include <QtGui/private/qzipreader_p.h>
#include <QtGui/private/qzipwriter_p.h>

压缩函数:

/*** @brief 压缩文件* @param fileNames 需要压缩的文件绝对路径* @param path 压缩后的文件的绝对路径*/
void zip_compress(const QStringList &fileNames, const QString &path) {QZipWriter *zipWriter = new QZipWriter(path);foreach (const QString &fileName, fileNames) {if (fileName.isEmpty()) continue;QFileInfo fileInfo(fileName);if (!fileInfo.exists()) continue;QFile file(fileName);if (!file.open(QIODevice::ReadOnly)) continue;zipWriter->addFile(fileInfo.fileName(), file.readAll());file.close();}zipWriter->close();if (zipWriter) {delete zipWriter;zipWriter = nullptr;}
}

解压函数:

/*** @brief 解压缩文件* @param fileName 需要解压缩的文件* @param path 解压后文件存放的目录*/
void zip_decompress(const QString &fileName, const QString &path) {if (fileName.isEmpty()) {return;}QFileInfo fileInfo(fileName);if (!fileInfo.exists()) {return;}QZipReader *reader = new QZipReader(fileName);foreach (const QZipReader::FileInfo &info, reader->fileInfoList()) {if (!info.isDir) {QString filePath =QDir::cleanPath(path + QDir::separator() + info.filePath);QFile file(filePath);if (!file.open(QIODevice::WriteOnly)) {continue;}file.write(reader->fileData(info.filePath));file.close();} else {QString dirName =QDir::cleanPath(path + QDir::separator() + info.filePath);QDir dir(dirName);if (!dir.exists()) dir.mkdir(dirName);}}reader->close();if (reader) {delete reader;reader = nullptr;}
}

7z

常用的解压软件比较多,例如winrar、7z、bandzip等等,其中7z是支持命令行形式的,详细命令可以看一下这两篇文章:

7z 命令行详解_7z命令-CSDN博客

前面我的这篇文章:Qt外部调用进程类QProcess的使用_windows qt 调用其它进程-CSDN博客 

就介绍过Qt如何通过QProcess调用外部进程,所以可以先安装7z然后使用QProcess调用7z应用程序,通过传参形式来压缩和解压缩文件,直接看代码:

压缩函数:

/*** @brief z7_compress 压缩函数* @param fileNames 需要压缩的文件的绝对路径* @param path 压缩后生成的压缩文件的绝对路径*/
void z7_compress(const QStringList &fileNames, const QString &path) {QProcess process(0);QStringList args;args.append("a");args.append(path);args.append(fileNames);args.append("-mx=3");process.start("7z.exe", args);//注意7z.exe的路径process.waitForStarted();process.waitForFinished();
}

解压缩函数: 

/*** @brief z7_decompress 解压缩函数* @param fileName 需要解压缩的压缩包路径* @param path 解压缩后生成的目录*/
void z7_decompress(const QString &fileName, const QString &path) {QProcess process(0);QStringList args;args.append("x");args.append(fileName);args.append("-o" + path);args.append("-aoa");process.start("7z.exe", args);//注意7z.exe的路径process.waitForStarted();process.waitForFinished();
}

ZLib

Qt压缩和解压缩文件也可以借助第三方库,zlib或者libzip,这里只介绍zlib。libzip有兴趣的也可以自己下去研究。

zlib 是一个开源的数据压缩库,广泛用于许多应用程序和系统中。以下是关于 zlib 的详细介绍:

  1. 功能

    • zlib 库提供了数据压缩和解压缩的功能,支持使用 DEFLATE 算法进行数据压缩。
    • zlib 提供了简单的 API,易于集成到各种应用程序中。
    • zlib 还支持在压缩数据中添加校验和,以确保数据的完整性。
  2. 特点

    • 高效性:zlib 使用 DEFLATE 算法进行数据压缩,具有较高的压缩比和压缩速度。
    • 跨平台性:zlib 可以在各种操作系统上运行,包括 Windows、Linux、macOS 等。
    • 开源性:zlib 是一个开源库,使用 zlib 的应用程序可以遵循 zlib 的开源许可协议。
  3. 使用场景

    • zlib 可用于在应用程序中对数据进行压缩,减小数据传输和存储的大小。
    • zlib 还可用于处理压缩文件格式,如 ZIP、PNG、HTTP 的 gzip 压缩等。
    • zlib 也常用于实时数据流的压缩,如网络传输中的数据压缩。
  4. API

    • zlib 提供了一组简单的 C 函数来进行数据压缩和解压缩,如 compress()uncompress()deflate()inflate() 等。
    • zlib 还提供了一些工具函数和数据结构,如 z_stream 结构体用于维护压缩和解压缩的状态。

首先需要下载zlib源码,zlib官网,下载之后解压然后准备编译:

使用Cmake:

 注意cmake对应vs,我电脑vs装的是VS2022,所以我这里选的是2022。

然后先Configure再Generate等待完成:

然后进入生成目录使用VS打开对应工程文件:

编译生成:

 注意debug和relase版本以及平台。

对应生成的库文件以及导入库文件:

 建立这样的一个文件目录结构,然后准备在代码中使用:

注意:zconf.h这个文件在cmake生成的文件目录里面 。dll动态库文件放在可执行文件同级目录下。

在工程文件中引入对应头文件以及库文件:

#引入zlib头文件和库
INCLUDEPATH += $PWD/zlib/includewin32 {LIBS += -L$$PWD/zlib/libCONFIG(release, debug|release) {LIBS += -lzlib}CONFIG(debug, debug|release) {LIBS += -lzlibd}
}

试一下zlib的压缩以及解压字符串函数。

压缩字符串:

static QByteArray compress(const QByteArray &data) {z_stream zs;memset(&zs, 0, sizeof(zs));if (deflateInit(&zs, Z_BEST_COMPRESSION) != Z_OK) { return QByteArray(); }zs.next_in = (Bytef *)data.constData();zs.avail_in = data.size();int ret;char outbuffer[32768];QByteArray outstring;do {zs.next_out = reinterpret_cast<Bytef *>(outbuffer);zs.avail_out = sizeof(outbuffer);ret = deflate(&zs, Z_FINISH);if (outstring.size() < zs.total_out) {outstring.append(outbuffer, zs.total_out - outstring.size());}} while (ret == Z_OK);deflateEnd(&zs);if (ret != Z_STREAM_END) { return QByteArray(); }return outstring;
}


解压缩字符串:

static QByteArray decompress(const QByteArray &data) {z_stream zs;memset(&zs, 0, sizeof(zs));if (inflateInit(&zs) != Z_OK) { return QByteArray(); }zs.next_in = (Bytef *)data.constData();zs.avail_in = data.size();int ret;char outbuffer[32768];QByteArray outstring;do {zs.next_out = reinterpret_cast<Bytef *>(outbuffer);zs.avail_out = sizeof(outbuffer);ret = inflate(&zs, 0);if (outstring.size() < zs.total_out) {outstring.append(outbuffer, zs.total_out - outstring.size());}} while (ret == Z_OK);inflateEnd(&zs);if (ret != Z_STREAM_END) { return QByteArray(); }return outstring;
}

测试压缩一个长字符串:

zlib的压缩与解压缩文件目前我网上搜的只能压缩和解压缩单个的,多个的目前没有找到,简单看一下压缩和解压缩的函数。

bool compress(const QString &fileName, const QString &zipFileName) {QFile inputFile(fileName);if (!inputFile.open(QIODevice::ReadOnly)) { return false; }gzFile zipFile = gzdopen(inputFile.handle(), "wb");if (!zipFile) { return false; }char buffer[1024];int bytesRead;while ((bytesRead = inputFile.read(buffer, sizeof(buffer))) > 0) {gzwrite(zipFile, buffer, bytesRead);}gzclose(zipFile);  // 关闭文件句柄inputFile.close(); // 关闭输入文件return true;
}bool decompress(const QString &zipFileName, const QString &fileName) {QFile inputFile(zipFileName);if (!inputFile.open(QIODevice::ReadOnly)) { return false; }QFile outputFile(fileName);if (!outputFile.open(QIODevice::WriteOnly)) { return false; }gzFile zipFile = gzdopen(inputFile.handle(), "rb");if (!zipFile) { return false; }char buffer[1024];int bytesRead;while ((bytesRead = gzread(zipFile, buffer, sizeof(buffer))) > 0) {if (outputFile.write(buffer, bytesRead) != bytesRead) { return false; }}gzclose(zipFile);inputFile.close();outputFile.close();return true;
}

那如果要压缩多个文件怎么办?这里可以使用QuaZip。

QuaZip

QuaZIP 是一个用于 Qt 框架的 C++ 库,它提供了对 ZIP 归档文件的读写功能。QuaZIP 是基于 zlib 和 minizip 库的封装,使得在 Qt 项目中可以方便地处理 ZIP 文件。也就是说QuaZIP是基于zlib的,使用QuaZIP的前提是已经编译好了zlib,zlib的编译前面已经讲了。这里直接开始讲QuaZIP的编译与使用。

首先下载QuaZIP,QuaZIP官网。下载之后进行解压:

可以看到里面有pro文件也有vs工程文件也有CMakeLists.txt文件,我们直接使用QtCreator来进行编译。首先因为QuaZIP依赖zlib,所以把刚刚编译的zlib文件放进来:

这个文件夹结构跟刚刚一样。

我们只编译库,所以进到这个目录:

 

把对应头文件放进来:

对应工程文件添加引入zlib:

然后开始编译生成对应debug和release版的库文件和导入库文件:

同样方法创建一个quazip文件夹,然后拷贝对应头文件以及导入库文件:

新建一个工程,将对应quazip文件放进工程文件夹内容,然后对应pro文件引入quazip头文件以及相关导入库文件:

INCLUDEPATH += $PWD/quazip/includewin32 {LIBS += -L$$PWD/quazip/libCONFIG(release, debug|release) {LIBS += -lquazip}CONFIG(debug, debug|release) {LIBS += -lquazipd}
}

对应动态库文件放入到可执行文件同级目录下:

注意:别忘了zlib的库文件,我测试用的debug版,所以理论上只放debug版对应zlib和QuaZIP的库文件就够了。

QuaZIP压缩和解压缩文件已经封装好了方法,比如将指定目录内的所有子目录以及文件压缩到指定压缩包内方法:

  \param fileCompressed The name of the archive.\param dir The directory to compress.\param recursive Whether to pack the subdirectories as well, orjust regular files.\return true if success, false otherwise.*/static bool compressDir(QString fileCompressed, QString dir = QString(), bool recursive = true);

对应的解压方法:

/**\param fileCompressed The name of the archive.\param dir The directory to extract to, the current directory ifleft empty.\return The list of the full paths of the files extracted, empty on failure.*/static QStringList extractDir(QString fileCompressed, QString dir = QString());/// Get the file list.

写一个简单的测试程序。

界面ui:

头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_openDir_clicked();void on_compress_clicked();void on_selectZip_clicked();void on_decompress_clicked();private:Ui::MainWindow *ui;
};
#endif  // MAINWINDOW_H

源文件: 

#include "mainwindow.h"
#include "quazip/include/JlCompress.h"
#include "ui_mainwindow.h"#include <QDebug>
#include <QDir>
#include <QFileDialog>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);
}MainWindow::~MainWindow() { delete ui; }void MainWindow::on_openDir_clicked() {QString dirPath =QFileDialog::getExistingDirectory(nullptr, QString(), QString());ui->dePath->setText(dirPath);
}void MainWindow::on_compress_clicked() {if (ui->dePath->text().isEmpty()) return;QDir deDir(ui->dePath->text());if (!deDir.exists()) return;if (deDir.isEmpty()) return;QString zipFileName = QDir::cleanPath(deDir.absolutePath() + QDir::separator() + deDir.dirName() + ".zip");bool r = JlCompress::compressDir(zipFileName, deDir.absolutePath());if (r)qDebug() << "compress success";elseqDebug() << "compress fail";
}void MainWindow::on_selectZip_clicked() {QString zipFileName = QFileDialog::getOpenFileName(nullptr, QString(), QString(), "Code Files (*.zip *.7z)");if (zipFileName.isEmpty()) return;ui->zipPath->setText(zipFileName);
}void MainWindow::on_decompress_clicked() {if (ui->zipPath->text().isEmpty()) return;QString zipFileName = ui->zipPath->text();if (!QFile::exists(zipFileName)) return;QFileInfo zipFileInfo(zipFileName);QString deDirPath =QDir::cleanPath(zipFileInfo.absolutePath() + QDir::separator() +zipFileInfo.completeBaseName());QDir deDir(deDirPath);if (!deDir.exists()) QDir().mkpath(deDirPath);QStringList fileList = JlCompress::extractDir(zipFileInfo.absoluteFilePath(),deDir.absolutePath());if (!fileList.isEmpty())qDebug() << "decompress success";elseqDebug() << "decompress fail";
}

测试一下:

没有问题,这个测试文件的代码我会上传,仅供参考,我编译的zlib以及QuaZIP的库文件也在里面,建议自己编译,因为平台或者编译软件可能与我不同,我的环境是Windows,VS2022,Qt5.15.2。

其他相关压缩以及解压缩这里就不做介绍了,有兴趣的可以下去自己研究一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/774962.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux 多个文件(csv)合并成一个文件(csv)

文章目录 前言实例:实战:另外&#xff0c;补充一个相关知识 总结 前言 Linux之cat合并多个文件 实例: # 将当前目录下所有csv结尾的文件合并到merge.csv cat *.csv > merge.csv # 当然也可以指定合并哪几个文件 cat db1.sql db2.sql db3.sql > db_all.sql 实战: 将每个…

好物视频素材哪里找?推荐以下几个自用很好的视频素材库

好物视频素材哪里找&#xff1f;这可是个让很多创作者头疼的问题。想制作一个吸引人的视频&#xff0c;好的素材可是关键。下面就给大家介绍几个热门的视频素材网站&#xff0c;希望能帮到你&#xff01; 蛙学网&#xff08;https://www.waxuewang.com/&#xff09;&#xff1…

国产数据库序列机制

数据库 达梦 序列&#xff1a;支持 主键自增&#xff1a;支持 使用序列 //1.创建序列 create sequence <序列名> increment by 10...; //2.使用序列&#xff0c;插入时指定&#xff0c;或者设计表字段默认值为seq1.nextval insert into <表名>(id,...) values…

netty构建udp服务器以及发送报文到客户端客户端详细案例

目录 一、基于netty创建udp服务端以及对应通道设置关键 二、发送数据 三、netty中的ChannelOption常用参数说明 1、ChannelOption.SO_BACKLOG 2、ChannelOption.SO_REUSEADDR 3、ChannelOption.SO_KEEPALIVE 4、ChannelOption.SO_SNDBUF和ChannelOption.SO_RCVBUF 5、Ch…

vs code

vs code 下载安装 https://code.visualstudio.com/https://code.visualstudio.com/ 下载完后&#xff0c;下一步下一步就安装完了&#xff0c;安装好后可以下载各种好用的插件

无需 VPN 即可急速下载 huggingface 上的 LLM 模型

无需 VPN 即可急速下载 huggingface 上的 LLM 模型 无需 VPN 即可急速下载 huggingface 上的 llm 模型安装依赖配置下载命令 无需 VPN 即可急速下载 huggingface 上的 llm 模型 快速下载huggingface模型&#xff1a; 安装依赖 pip install -U huggingface_hub hf_transfer …

已注册的商标别忘了续展,新注可能难下证!

近期普推知产老杨遇到好几个网友和看过多个案例&#xff0c;以前商标名称可以申请注册下来&#xff0c;但是换字体注册不下来了&#xff0c;有的是不想续展想直接换字体申请注册&#xff0c;但是也没有下来。 这些商标名称主要是存在禁止注册或缺显&#xff0c;比如“柳林”以前…

蓝桥杯每日一题:修建灌木

题目来源: 第十三届蓝桥杯大赛软件赛省赛B组 爱丽丝要完成修建灌木的工作 有 N N N 棵灌木整齐的从左向右排成一排, 爱丽丝在每天傍晚会修建一棵灌木, 让灌木的高度变为 0 厘米. 修建灌木的顺序是从最左侧的灌木开始, 每天向右修建一棵灌木. 当修建了最右侧的灌木之后, 她会调…

ensp静态路由综合实验(一)

实验拓扑&#xff1a; 实验目的&#xff1a; 1、R6为ISP&#xff0c;接口IP地址均为公有地址&#xff0c;该设备只能配置IP地址&#xff0c;之后不能再对其进行任何配置&#xff1b; 2、R1-R5为局域网&#xff0c;私有IP地址192.168.1.0/24&#xff0c;请合理分配&#xff1b;…

Web API —— BOM 学习(完结)

目录 一、BOM 介绍 二、Window 对象 &#xff08;一&#xff09;基本介绍 &#xff08;二&#xff09;定时器 —— 延时函数 1.语法 2.清除时间函数 3.和 interval 间歇函数的区别 &#xff08;三&#xff09;JS 执行机制 1.介绍 2.同步任务 3.异步任务 4.执行过程…

Go与Java深度对比:从语言特性到应用场景的全面分析

Go&#xff08;Golang&#xff09;和Java是两种流行的编程语言&#xff0c;它们在设计哲学、应用领域和生态系统方面有着独特的特点。以下是对这两种语言的全方位对比&#xff1a; 语言历史与发展 Go&#xff1a; Go语言由Robert Griesemer、Rob Pike和Ken Thompson在2007年…

编程出现bug?怎么用Python打印异常

在 Python 编程中&#xff0c;异常是指程序执行过程中出现的错误或异常情况。当程序遇到异常时&#xff0c;为了更好地调试和定位问题&#xff0c;我们需要打印异常信息。本文将详细介绍如何在 Python 中打印异常&#xff0c;并提供一些示例和注意事项。 一、try-except 语句捕…

一、CentOS基础命令(2.系统与用户操作)

文章目录 2、用户管理&#xff08;1.&#xff09;useradd - 创建新用户&#xff08;2.&#xff09;userdel - 删除用户&#xff08;3.&#xff09;usermod - 修改用户属性&#xff08;4.&#xff09;passwd - 管理用户密码&#xff08;5.&#xff09;groupadd - 创建用户组&…

C语言程序编译和链接的

目录 引言 编译与链接概览 编译过程详解 链接过程解读 结论 引言 在编程实践中&#xff0c;《程序员的自我修养》一书为我们揭示了构建高质量软件背后的重要环节——编译与链接。这两个过程对于C语言程序从源代码到可执行文件的蜕变至关重要&#xff0c;它们是每一个开发…

python ACM格式 || stdin和input的区别 || acm中常用的函数

疑问 在acm格式里有两种方法读取用户输入&#xff1a; import sys 然后使用 sys.stdininput() 但隐隐约约感觉这两个方法读到的数据在最后一行有些问题 导致我在使用stdin时候&#xff0c;需要使用正则表达式&#xff1a;re.split(‘[,\n]’,textline)来把一个以逗号分割的字…

C++资产设备管理系统

一、引言 1.1 项目设计背景及意义 1.1.1理论研究基础 &#xff08;1&#xff09;C在C的基础上增加了面向对象的机制。 &#xff08;2&#xff09;充分利用面向对象机制中的多态性实现函数的设计。 1.1.2 技术层面的支持 运用系统为C面向对象程序设计提供的各种设计方法和V…

24.park和unpark方法

1.park方法可以暂停线程&#xff0c;线程状态为wait。 2.unpark方法可以恢复线程&#xff0c;线程状态为runnable。 3.LockSupport的静态方法。 4.park和unpark方法调用不分先后&#xff0c;unpark先调用&#xff0c;park后执行也可以恢复线程。 public class ParkDemo {pu…

冗余双写方案下数据一致性问题解决及延申问题处理方案

主要整理了采用冗余双写方案后的问题解决方案。 1、问题&#xff1a;冗余双写场景下&#xff0c;如何解决数据一致性问题&#xff1f; 方案一&#xff1a; 直接RPC调用Seata分布式事务框架&#xff0c;采用该方式实现了事务的强一致性&#xff0c;代码逻辑简单的同时业务侵入…

【题解】—— LeetCode一周小结12

【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结11 18.区域和检索 - 数组不可变 题目链接&#xff1a;303. 区域和检索 - 数组不可变 1.计算索引 left 和 right &#xff08;包含 left 和 right&#xff09;之间的 nums 元素的 和 &#xff0c;其…

2024年腾讯云服务器租用价格_轻量和CVM报价

腾讯云服务器价格表2024年最新价格&#xff0c;轻量2核2G3M服务器61元一年、2核2G4M服务器99元1年&#xff0c;三年560元、2核4G5M服务器165元一年、3年900元、轻量4核8M12M服务器646元15个月、4核16G10M配置32元1个月、8核32G配置115元1个月&#xff0c;345元3个月。CVM云服务…