赞
踩
前面讲了很多Qt的文件操作,文件操作自然就包括压缩与解压缩文件了,正好最近项目里要用到压缩以及解压缩文件,所以就研究了一下Qt如何压缩与解压缩文件。
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;
- }
- }
常用的解压软件比较多,例如winrar、7z、bandzip等等,其中7z是支持命令行形式的,详细命令可以看一下这两篇文章:
前面我的这篇文章: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();
- }
Qt压缩和解压缩文件也可以借助第三方库,zlib或者libzip,这里只介绍zlib。libzip有兴趣的也可以自己下去研究。
zlib 是一个开源的数据压缩库,广泛用于许多应用程序和系统中。以下是关于 zlib 的详细介绍:
功能:
特点:
使用场景:
API:
compress()
, uncompress()
, deflate()
, inflate()
等。z_stream
结构体用于维护压缩和解压缩的状态。首先需要下载zlib源码,zlib官网,下载之后解压然后准备编译:
使用Cmake:
注意cmake对应vs,我电脑vs装的是VS2022,所以我这里选的是2022。
然后先Configure再Generate等待完成:
然后进入生成目录使用VS打开对应工程文件:
编译生成:
注意debug和relase版本以及平台。
对应生成的库文件以及导入库文件:
建立这样的一个文件目录结构,然后准备在代码中使用:
注意:zconf.h这个文件在cmake生成的文件目录里面 。dll动态库文件放在可执行文件同级目录下。
在工程文件中引入对应头文件以及库文件:
- #引入zlib头文件和库
- INCLUDEPATH += $PWD/zlib/include
-
- win32 {
- LIBS += -L$$PWD/zlib/lib
- CONFIG(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 是一个用于 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/include
-
- win32 {
- LIBS += -L$$PWD/quazip/lib
- CONFIG(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, or
- just 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 if
- left 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_NAMESPACE
-
- class MainWindow : public QMainWindow {
- Q_OBJECT
-
- public:
- 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";
- else
- qDebug() << "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";
- else
- qDebug() << "decompress fail";
- }
测试一下:
没有问题,这个测试文件的代码我会上传,仅供参考,我编译的zlib以及QuaZIP的库文件也在里面,建议自己编译,因为平台或者编译软件可能与我不同,我的环境是Windows,VS2022,Qt5.15.2。
其他相关压缩以及解压缩这里就不做介绍了,有兴趣的可以下去自己研究一下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。