前言
最近在做項目時遇到一個需求,需要將升級的文件壓縮成zip,再進行傳輸;
通過網絡調研,有許多方式可以實現,例如QT私有模塊的ZipReader、QZipWriter;或者第三方庫zlib或者libzip或者quazip等;其中libzip和quazip都是依賴于zlib;
然后,這些都需要變成庫,然后再鏈接到QT項目中進行使用;
由于項目的特殊性,有可能需要在window,Linux和ARM三個平臺上去運行,如果都編譯為庫去使用的話,那么需要編譯三個平臺,甚是麻煩,而且如果系統版本不一樣,可能還不能用;
所以,現階段有兩種方案,其一是使用QT自帶的壓縮庫,其二是使用第三方庫的源碼;
由此可知,使用QT自帶的私有庫是最方便,且網絡上也有教程(文章最后也提供的操作代碼);
但是,使用QT自帶的私有庫有幾個缺點,第一是需要QT5.14以上的版本才可以使用,且在QT6中已經移除了該模塊;而且需要安裝QT時勾選安裝QT源碼才可以使用;由此,這種方式pass掉;
本人在ARM平臺安裝QT,是使用命令行在線安裝的,QT的版本無法控制,也無法安裝源碼!
只能使用第二種方式了,遂在網絡上尋找第三方庫的源碼,如何將將源碼潛入到QT項目中去;
網絡上教程,百分之99.99都是叫你如何編譯使用的,剩下百分之0.01是需要vip和付費資源,完全沒有使用源碼的方式;
直到我遇到了一篇博客,里面博主就是使用Quazip+Zlib源碼,用于異步壓縮文件為zip格式,且博主將代碼開源,正好符合我的需求,再次非常感謝該博主,鏈接如下:
Qt+Quazip+Zlib源碼工程實現帶進度同步異步加解壓文件_qt 壓縮zip 進度-CSDN博客
但是,該項目源碼也使用到了QT的私有模塊,對于我這種在ARM平臺下使用命令行安裝的QT,且版本沒有達到5.14的我來說,無疑是晴天霹靂;
項目無法運行,報錯!!!
沒辦法,只能自己手動去修改,這難不倒身為程序員的我!
我將代碼中的私有模塊去掉,將博主寫的壓縮解壓縮代碼也去掉,自己動手寫了一個操作類,使用了Quazip的接口,供外部使用!(同步 壓縮/解壓縮)
完成后,突然想起來,還有加密壓縮的需求,這該怎么辦呢?
在網絡上調研了一整天,沒啥博客能講明白或者能使用quazip庫直接給出代碼的;
直到我遇到了另一篇博客,里面有分享了一些?加密壓縮多個文件 和?解壓含密碼的壓縮文件 的案例;
通過參考這些案例,我寫出來自己的加密壓縮和解密壓縮文件和文件夾的操作函數,經過測試可行;
再次也非常感謝該博主的分享,博文鏈接如下:
Qt加密壓縮與解壓-CSDN博客
到了這一步,項目需求的加密壓縮和解密壓縮基本就完成了;
但轉念一想,平常事我們使用的解壓縮軟件時,都是帶有進度條的,也就是說下解壓縮時,我們應該需要知道進度;
于是乎,再次修改代碼,增加了解壓縮操作時,將當前進度通過信號發射出去,由調用方處理這個信號即可!
因為我實現的解壓縮功能是同步的,所以,調用方在處理解壓縮時,如果不希望卡屏,就得使用線程去操作;
由此寫出了一個簡易的解壓縮zip軟件,運行效果如下:
壓縮成功后
解壓縮和壓縮文件是一樣的,這里就不放出演示了!
對比一下壓縮后的大小:
效果還是很明顯的!
目錄
前言
一、基礎的解壓縮
二、自定義實現解壓縮
1.加密壓縮
1).打開zip文件
2).獲取需要壓縮的文件夾內部的所有文件及子文件
3).創建一個QuaZipFile?
4).遍歷獲取到的所有文件列表
5).創建新的ZIP文件條目信息
6).打開ZIP文件條目
7).讀取寫入
8).關閉文件
9).詳細代碼
2.解密解壓縮
1).創建文件夾
?2).打開zip文件
3).獲取zip內的所有文件條目
4).遍歷這個鏈表
5).處理文件夾
?6).創建一個QuaZipFile?
7).打開QuaZipFile
8).讀取寫入(解壓縮)
?9).關閉文件
10).詳細代碼
三、源碼分享
1.下載后如何引入自己的項目工程中?
1).拷貝quazip文件夾到自己的項目工程中
2).在自己的項目的.pro文件引入如下代碼
3).包含頭文件
2.QT自帶壓縮庫操作分享 ZipReader、QZipWriter
1).導入私有模塊
2).zipcompress.h
3).zipcompress.cpp
四、結束語
一、基礎的解壓縮
網絡上介紹Quazip庫使用的,基本都是以下這些:
JlCompress mJlCompress;// 壓縮文件
mJlCompress.compressFiles(fileCompressed,files);// 解壓文件夾
mJlCompress.extractDir(fileCompressed, dir);// 壓縮文件夾
mJlCompress.compressDir(fileCompressed, dir, recursive);// 解壓文件
mJlCompress.extractFiles(fileCompressed, files);
其實如果是基礎用法,上面這幾句代碼也夠用了;
但是如果涉及到加密壓縮和進度方面,就得自己去實現解壓縮的過程了,且這樣也更加靈活一點!
二、自定義實現解壓縮
Quazip庫還提供了QuaZip、QuaZipFile、QuaZipNewInfo、QuaZipFileInfo
等類供我們自己去處理!
QuaZip 類用于打開一個.zip文件;
QuaZipFile 類用于處理zip內部的文件,即讀取zip內部文件數據(解壓)或者往zip內部寫入文件(壓縮);【在此可以進行加密和解密處理】
QuaZipNewInfo 類用于定義一個zip的文件信息,在壓縮時使用;
QuaZipFileInfo 類用于處理一個zip內部的文件;
當然,還有以下這么多:(別家復制過來的)
類 | 說明 |
---|---|
JlCompress | 典型操作工具類 |
QuaAdler32 | Adler32算法校驗和 |
QuaChecksum32 | 校驗和接口 |
QuaCrc32 | CRC32校驗和 |
QuaGzipFile | GZIP 文件操作 |
QuaZIODevice | 壓縮/解壓 QIODevice |
QuaZip | ZIP 文件 |
QuaZipDir | ZIP文件內目錄導航 |
QuaZipFile | ZIP文件內的文件 |
QuaZipFileInfo | ZIP壓縮包內的文件信息 |
QuaZipFilePrivate | QuaZip的接口 |
QuaZipNewInfo | 被創建的文件信息 |
QuaZipPrivate | QuaZIP內部類 |
下面是加密壓縮和解密壓縮的過程分析;
1.加密壓縮
這里處理的是壓縮文件夾,壓縮文件與之類似;
壓縮后的文件結構與原來一致;
1).打開zip文件
QuaZip newZip(fileCompressed); // 要生成的zip文件
if (!newZip.open(QuaZip::mdCreate)) { qDebug() << "Failed to create ZIP file:" << fileCompressed; return false;
}
參數枚舉介紹:
enum Mode {mdNotOpen, ///< ZIP文件未打開。這是初始模式。mdUnzip, ///< ZIP文件已打開,用于讀取其內部的文件。mdCreate, ///< ZIP文件已通過open()調用創建。mdAppend, ///< ZIP文件以追加模式打開。這指的是ZIP/UNZIP包中的APPEND_STATUS_CREATEAFTER模式,/// 意味著zip被追加到某個已存在的文件中,該文件包含自解壓代碼。這顯然不是您想要用來/// 向現有的ZIP歸檔添加文件的模式。mdAdd ///< ZIP文件已打開,用于向歸檔中添加文件。
};
一般來說,我們只需要用到 mdUnzip 用于解壓縮 和 mdCreate 用于壓縮即可!
2).獲取需要壓縮的文件夾內部的所有文件及子文件
QStringList filePathList = 獲取所有文件();
3).創建一個QuaZipFile?
QuaZipFile zipFile(&newZip);
使用QuaZip作為參數;
4).遍歷獲取到的所有文件列表
在循環體內部處理壓縮事項;以下操作都是在循環體內部進行;
5).創建新的ZIP文件條目信息
QuaZipNewInfo info(文件名, 文件路徑+文件名);
6).打開ZIP文件條目
if (!zipFile.open(QIODevice::WriteOnly, info, password.toUtf8().constData(), 0, 8)) { qDebug() << "Failed to open ZIP entry for writing:" << fileName; // 關閉ZIP newZip.close(); return false;
}
open參數介紹:
bool open(OpenMode mode, // 打開模式,指定是以什么方式打開文件(例如,只寫、追加等)const QuaZipNewInfo& info, // 文件信息,包括文件名、時間戳等const char *password = nullptr, // 密碼,用于加密文件,如果不需要加密則傳遞nullptrquint32 crc = 0, // CRC校驗碼,通常設置為0,除非在原始模式下使用int method = Z_DEFLATED, // 壓縮方法,Z_DEFLATED表示使用Deflate算法,Z_BZIP2ED表示使用BZIP2算法,0表示不壓縮int level = Z_DEFAULT_COMPRESSION, // 壓縮級別,對于Deflate算法,可以是0-9之間的值,Z_DEFAULT_COMPRESSION表示默認級別// 以下保持默認即可!!!bool raw = false, int windowBits = -MAX_WBITS, int memLevel = DEF_MEM_LEVEL,int strategy = Z_DEFAULT_STRATEGY
);
需要注意的是,
src參數,通常設置為0,除非你知道使用其他值,所帶來的后果;
method參數,需要設置為8,即宏Z_DEFLATED,這個是壓縮算法,注意,quazip只支持這種算法,所以必須設置為8;
level參數,是壓縮等級,可設置0-9,之間的任何一個數字,0表示無壓縮,最快,9表示最大壓縮,但最慢,一般設置為默認值即可!
其實也就是說,只需要設置前面三個參數即可!!!
7).讀取寫入
使用QFile讀取本地文件數據,寫入QuaZipFile中
QFile sourceFile(filePath);
sourceFile.open(QIODevice::ReadOnly);
zipFile.write(sourceFile.readAll()); // 注意,處理大文件時,這里會崩潰
注意,上面寫法在處理大文件時會有問題,readAll()函數會將文件數據讀如內存中,如果文件太大,會將堆內存給撐爆,程序就閃退了;
所以為了避免這樣的問題,在處理大文件時,必須分塊進行處理!
QByteArray buffer;
while(!sourceFile.atEnd()) { buffer = sourceFile.read(4096); // 每次讀取一頁內存數據 zipFile.write(buffer);
}
8).關閉文件
最后記得在循環尾部將文件關閉后,再進行新一輪的文件讀寫操作!
sourceFile.close();
zipFile.close();
處理完畢后,記得關閉 newZip.close();
加密壓縮文件部分與之類似,這里就不展開講解了!
給出函數接口,自己動手去實現一下吧;
/*** @brief 加密壓縮多個文件* @param fileCompressed 壓縮包名* @param files 要解壓的文件列表* @param password 密碼* @return*/bool compressFilesWithPassword(const QString &fileCompressed,const QStringList &files,const QString& password);
9).詳細代碼
進度部分就不詳細講解了,都在代碼函數中
/** * @brief 加密壓縮文件夾內的所有文件 * @param fileCompressed 壓縮包名-路徑 * @param dir 壓縮路徑 * @param password 密碼 * @return */
bool zipCompress::compressDirsWithPassword(const QString &fileCompressed, const QString &dir, const QString &password) {bool result = false;if (fileCompressed.isEmpty() || dir.isEmpty()) {emit signalCompressDirinish(result);return result;}QuaZip newZip(fileCompressed); // 要生成的zip文件if (!newZip.open(QuaZip::mdCreate)) {qDebug() << "Failed to create ZIP file:" << fileCompressed;emit signalCompressDirinish(result);return result;}// 讀取目錄中的所有文件QStringList filePathList = listFilesInDirectoryRecursively(dir);if (filePathList.isEmpty()) {qDebug() << "No files to compress in directory:" << dir;newZip.close();emit signalCompressDirinish(result);return result;}qreal pro = 100.0 / filePathList.size();qreal progress = 1.0;QuaZipFile zipFile(&newZip);for (const QString &filePath : filePathList) {// 構造相對于dir的文件名QString fileName = QDir(dir).relativeFilePath(filePath);// 創建ZIP文件條目信息QuaZipNewInfo info(fileName, filePath);// 嘗試打開ZIP文件條目進行寫入if (!zipFile.open(QIODevice::WriteOnly, info, password.toUtf8().constData(), 0, 8)) {qDebug() << "Failed to open ZIP entry for writing:" << fileName;// 關閉ZIPnewZip.close();emit signalCompressDirinish(result);return result;}// 打開源文件進行讀取QFile sourceFile(filePath);if (!sourceFile.open(QIODevice::ReadOnly)) {qDebug() << "Failed to open source file for reading:" << filePath;// 關閉ZIPnewZip.close();emit signalCompressDirinish(result);return result;}// 總進度emit signalCompressionProgress(progress, "1", filePath);// 大文件讀取分塊處理,否則程序會閃退{qreal file_pro = 100.0 / (sourceFile.size() / mBlockSize);qreal file_progress = 0.0;// 將源文件的內容寫入ZIP文件QByteArray buffer;while(!sourceFile.atEnd()) {buffer = sourceFile.read(mBlockSize);zipFile.write(buffer);file_progress += file_pro;emit signalFileProgress(file_progress, filePath);}emit signalFileProgress(100, filePath);}sourceFile.close();zipFile.close();progress += pro;progress = qBound(0.0, progress, 99.999);}result = true;newZip.close();emit signalCompressionProgress(100, "1", "");emit signalCompressDirinish(result);return result;
}QStringList zipCompress::listFilesInDirectoryRecursively(const QString &directoryPath) {QStringList list;QDirIterator it(directoryPath, QDir::Files, QDirIterator::Subdirectories);while (it.hasNext()) {QString filePath = it.next();list.append(filePath);}return list;
}
2.解密解壓縮
這里處理的是解壓縮一個zip文件;
解壓出來文件結構與壓縮包內一致!
1).創建文件夾
判斷傳進來的路徑解壓路徑,如果不存在則創建
?2).打開zip文件
QuaZip zip(fileCompressed);
if (!zip.open(QuaZip::mdUnzip)) { qDebug() << "Failed to open ZIP file:" << fileCompressed; return false;
}
因為是解壓縮,所以參數使用mdUnzip
3).獲取zip內的所有文件條目
QList<QuaZipFileInfo> fileInfoList = zip.getFileInfoList();
4).遍歷這個鏈表
解壓縮操作都在這個循環體內進行;
5).處理文件夾
如果處理的當前文件,在本機電腦中還沒有路徑,則進行創建;
且跳過是文件夾的操作!
?6).創建一個QuaZipFile?
QuaZipFile zipFile(zip.getZipName(), 文件名);
7).打開QuaZipFile
zipFile.open(QIODevice::ReadOnly, password.toUtf8().constData());
參數二是密碼;
8).讀取寫入(解壓縮)
注意,為了防止大文件的問題,讀取寫入是還是分塊進行操作!?
QByteArray buffer;
while(!zipFile.atEnd()) { buffer = zipFile.read(4096); outFile.write(buffer);
}
?9).關閉文件
最后記得在循環尾部將文件關閉后,再進行新一輪的文件讀寫操作!
outFile.close();
zipFile.close();
處理完畢后,記得關閉 zip.close();
10).詳細代碼
進度部分就不詳細講解了,都在代碼函數中
bool zipCompress::extractDirWithPassword(const QString &fileCompressed, const QString &dir, const QString &password) {bool result = false;if (fileCompressed.isEmpty() || dir.isEmpty()) {emit signalExtractDirFinish(result);return result;}// 使用QFileInfo獲取文件名(不帶擴展名)并構建目標目錄路徑QFileInfo fileInfo(fileCompressed);QString targetDirName = fileInfo.completeBaseName();QString targetDirPath = QDir(dir).absoluteFilePath(targetDirName);// 創建目標目錄(如果不存在)QDir targetDir(targetDirPath);if (!targetDir.exists() && !targetDir.mkpath(".")) {qDebug() << "Failed to create target directory:" << targetDirPath;emit signalExtractDirFinish(result);return result;}// 打開ZIP文件QuaZip zip(fileCompressed);if (!zip.open(QuaZip::mdUnzip)) {qDebug() << "Failed to open ZIP file:" << fileCompressed;emit signalExtractDirFinish(result);return result;}// 遍歷ZIP文件中的所有條目QList<QuaZipFileInfo> fileInfoList = zip.getFileInfoList();qreal pro = 100.0 / fileInfoList.size();qreal progress = 1.0;for (const QuaZipFileInfo &fileInfoEntry : fileInfoList) {// 組合目標文件路徑QString fileName = fileInfoEntry.name;QString filePath = targetDir.absoluteFilePath(fileName);// 如果是文件夾,如果不存在則創建;然后跳過文件夾的操作QFileInfo info(filePath);if (info.isDir()) {QDir().mkpath(filePath);continue;} else { // 如果是文件,如果路徑不存在,創建該路徑QString path = info.path();QDir dpath(path);if (!dpath.exists()) {if (!dpath.mkpath(path)) {qDebug() << "Failed to create directory:" << path;emit signalExtractDirFinish(result);return result;}}}// 打開ZIP條目并解壓文件QuaZipFile zipFile(zip.getZipName(), fileName);if (zipFile.open(QIODevice::ReadOnly, password.toUtf8().constData())) {QFile outFile(filePath);if (!outFile.open(QIODevice::WriteOnly)) {qDebug() << "Failed to open output file for writing:" << filePath;zipFile.close();zip.close();emit signalExtractDirFinish(result);return result;}emit signalCompressionProgress(progress, "2", filePath);// 大文件讀取分塊處理,否則程序會閃退{qreal file_pro = 100.0 / (zipFile.size() / mBlockSize);qreal file_progress = 0.0;// 解壓并寫入文件QByteArray buffer;while(!zipFile.atEnd()) {buffer = zipFile.read(mBlockSize);outFile.write(buffer);file_progress += file_pro;emit signalFileProgress(file_progress, filePath);}emit signalFileProgress(100, filePath);}outFile.close();zipFile.close();} else {qDebug() << "Failed to open ZIP entry for reading:" << fileName;zip.close();emit signalExtractDirFinish(result);return result;}progress += pro;progress = qBound(0.0, progress, 99.999);}result = true;// 關閉ZIP文件zip.close();emit signalCompressionProgress(100, "2", "");emit signalExtractDirFinish(result);return result;
}
三、源碼分享
到此,解壓縮已經介紹完畢,現在分享我參考寫的解壓縮程序
https://download.csdn.net/download/cpp_learner/90411497https://download.csdn.net/download/cpp_learner/90411497因為我這邊編寫的壓縮和解壓縮操作都是同步的,所以,建議操作時使用線程去處理,否則會卡屏,而且進度條也無法使用;
在我給出的案例工程中,就是使用了線程去解壓縮等操作,有興趣可以學習一下!
1.下載后如何引入自己的項目工程中?
1).拷貝quazip文件夾到自己的項目工程中
2).在自己的項目的.pro文件引入如下代碼
# 源碼方式使用需要設置為靜態庫
DEFINES += QUAZIP_STATIC
include($$PWD/quazip/3rdparty/zlib.pri)
include($$PWD/quazip/quazip.pri)
include($$PWD/quazip/zipop/zipop.pri)
3).包含頭文件
#include "zipcompress.h"
頭文件包含后,就可以直接使用了?
compressionTool::zipCompress m_zipCompress;
// 壓縮文件夾
m_zipCompress.compressDirsWithPassword(mZipPath, mPath, mPassword); // 解壓縮
m_zipCompress.extractDirWithPassword(fileName, fileinfo.path(), "abc@123"); // 壓縮文件
m_zipCompress.compressFilesWithPassword(mZipPath, mFiles, mPassword);
2.QT自帶壓縮庫操作分享 ZipReader、QZipWriter
以下是我編寫好的操作類,直接新建文件拷貝代碼到文件中即可使用!
(注意,一般來說,需要QT5.14以上的版本才可以使用)
1).導入私有模塊
在.pro文件中添加私有模塊
QT += gui-private
2).zipcompress.h
#ifndef ZIPCOMPRESS_H
#define ZIPCOMPRESS_H#include <QObject>
#include <QtGui/private/qzipreader_p.h>
#include <QtGui/private/qzipwriter_p.h>class ZipCompress : public QObject
{Q_OBJECT
public:ZipCompress(QObject *parent = nullptr);/*** @brief 壓縮文件* @param fileNames 需要壓縮的文件名* @param saveName 壓縮后的文件路徑和名字*/bool zipCompressFile(const QStringList &fileNames, const QString &saveName);/*** @brief 壓縮文件夾* @param dirName 需要壓縮的文件夾名* @param saveName 壓縮后的文件路徑和名字*/bool zipCompressDirector(const QString &dirName, const QString &saveName);/*** @brief 解壓縮* @param zipFile 壓縮包* @param saveDir 解壓路徑* @return*/bool zipUnCompressFile(const QString &zipFile, const QString &saveDir);private:/*** @brief 遞歸壓縮* @param zipWriterHandle QZipWriter指針* @param zipParentDirName 父路徑,相對路徑* @param srcDir 當前需要處理的文件夾路徑,絕對路徑*/void zipCompressDirector(void *zipWriterHandle, const QString &zipParentDirName, const QString &srcDir);private:QZipReader *mZipReader;QZipWriter *mZipWriter;
};#endif // ZIPCOMPRESS_H
3).zipcompress.cpp
#include "zipcompress.h"#include <QFileInfo>
#include <QDir>
#include <QDebug>ZipCompress::ZipCompress(QObject *parent): QObject(parent)
{
}bool ZipCompress::zipCompressFile(const QStringList &fileNames, const QString &saveName)
{QZipWriter *zipWriter = new QZipWriter(saveName);if (!zipWriter) {qDebug() << "壓縮失敗!";return false;}QFile file;QFileInfo fileInfo;foreach (const QString &fileName, fileNames) {if (fileName.isEmpty() || "" == fileName) {continue;}// 判斷文件是否存在fileInfo.setFile(fileName);if (!fileInfo.exists()) {qDebug() << fileName << " : 文件不存在!";continue;}if (fileInfo.isFile()) {// 打開文件file.setFileName(fileName);if (!file.open(QIODevice::ReadOnly)) {qDebug() << fileName << " : 文件打開失敗!";continue;}// 添加到壓縮包中zipWriter->addFile(fileInfo.fileName(), file.readAll());file.close();} else if (fileInfo.isDir()) {// 添加到壓縮包中zipWriter->addDirectory(fileName);}}zipWriter->close();if (zipWriter) {delete zipWriter;zipWriter = nullptr;}return true;
}bool ZipCompress::zipCompressDirector(const QString &dirName, const QString &saveName)
{QFile file(saveName);if (!file.open(QFile::WriteOnly)) {qDebug() << "壓縮失敗!";return false;}std::shared_ptr<QZipWriter> zipWriter(new QZipWriter(&file));if (!zipWriter) {qDebug() << "壓縮失敗!";return false;}zipCompressDirector(zipWriter.get(), "", dirName);zipWriter->close();file.close();return true;
}bool ZipCompress::zipUnCompressFile(const QString &zipFile, const QString &saveDir)
{QFile file(zipFile);if (!file.open(QIODevice::ReadOnly)) {qDebug() << zipFile << " : 文件打開失敗!";return false;}QDir dir(saveDir);if (!dir.exists()) {if (!dir.mkpath(saveDir)) { // 創建文件夾qDebug() << saveDir << " : 文件夾路徑不存在,且創建失敗!";return false;}}std::shared_ptr<QZipReader> zipReader(new QZipReader(&file));return zipReader->extractAll(saveDir); // 全部解壓出來
}void ZipCompress::zipCompressDirector(void *zipWriterHandle, const QString &zipParentDirName, const QString &srcDir)
{QZipWriter *zipWriter = (QZipWriter *)zipWriterHandle;QDir directory(srcDir);QFileInfoList fileList = directory.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);for (const QFileInfo &fileInfo : fileList) {QString relatePath = fileInfo.fileName(); // 獲取當前文件名 | 文件夾名if (!zipParentDirName.isEmpty()) {relatePath.prepend(zipParentDirName + "/"); // 頭部拼接上父路徑,相對路徑}QString filePath = fileInfo.absoluteFilePath(); // 獲取當前文件的絕對路徑if (fileInfo.isDir()) {// 添加文件夾zipWriter->addDirectory(relatePath);// 參數二:文件夾相對路徑 參數三:文件夾絕對路徑zipCompressDirector(zipWriter, relatePath, filePath);} else {QFile file(filePath);if (!file.open(QIODevice::ReadOnly)) {qDebug() << filePath << " : 文件打開失敗!";continue;}zipWriter->addFile(relatePath, file.readAll());file.close();}}
}
四、結束語
文章最后,感謝各位能夠堅持看完,相信此篇文章也會對你有所幫助;
當然,我上面所給出的只是一些基礎用法,還有很多高級用法我也還沒整明白;
或者哪位大佬有更好的實現方式,也歡迎評論區分享出來,供大家一起探討學習;
完!