It is mainly a recursive algorithm that serializes data into a single file, each with its relative path to the parent folder. And deserializing is just taking binary data, creating needed subfolders, and saving the file.
Download: QtFolderCompressor.zip
[FolderCompressor.h]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #ifndef FOLDERCOMPRESSOR_H #define FOLDERCOMPRESSOR_H #include <QFile> #include <QObject> #include <QDir> class FolderCompressor : public QObject { Q_OBJECT public : explicit FolderCompressor(QObject *parent = 0); //A recursive function that scans all files inside the source folder //and serializes all files in a row of file names and compressed //binary data in a single file bool compressFolder(QString sourceFolder, QString destinationFile); //A function that deserializes data from the compressed file and //creates any needed subfolders before saving the file bool decompressFolder(QString sourceFile, QString destinationFolder); private : QFile file; QDataStream dataStream; bool compress(QString sourceFolder, QString prefex); }; #endif // FOLDERCOMPRESSOR_H |
[FolderCompressor.cpp]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #include "FolderCompressor.h" FolderCompressor::FolderCompressor(QObject *parent) : QObject(parent) { } bool FolderCompressor::compressFolder(QString sourceFolder, QString destinationFile) { QDir src(sourceFolder); if (!src.exists()) //folder not found { return false ; } file.setFileName(destinationFile); if (!file.open(QIODevice::WriteOnly)) //could not open file { return false ; } dataStream.setDevice(&file); bool success = compress(sourceFolder, "" ); file.close(); return success; } bool FolderCompressor::compress(QString sourceFolder, QString prefex) { QDir dir(sourceFolder); if (!dir.exists()) return false ; //1 - list all folders inside the current folder dir.setFilter(QDir::NoDotAndDotDot | QDir::Dirs); QFileInfoList foldersList = dir.entryInfoList(); //2 - For each folder in list: call the same function with folders' paths for ( int i=0; i<foldersList.length(); i++) { QString folderName = foldersList.at(i).fileName(); QString folderPath = dir.absolutePath()+ "/" +folderName; QString newPrefex = prefex+ "/" +folderName; compress(folderPath, newPrefex); } //3 - List all files inside the current folder dir.setFilter(QDir::NoDotAndDotDot | QDir::Files); QFileInfoList filesList = dir.entryInfoList(); //4- For each file in list: add file path and compressed binary data for ( int i=0; i<filesList.length(); i++) { QFile file(dir.absolutePath()+ "/" +filesList.at(i).fileName()); if (!file.open(QIODevice::ReadOnly)) //couldn't open file { return false ; } dataStream << QString(prefex+ "/" +filesList.at(i).fileName()); dataStream << qCompress(file.readAll()); file.close(); } return true ; } bool FolderCompressor::decompressFolder(QString sourceFile, QString destinationFolder) { //validation QFile src(sourceFile); if (!src.exists()) { //file not found, to handle later return false ; } QDir dir; if (!dir.mkpath(destinationFolder)) { //could not create folder return false ; } file.setFileName(sourceFile); if (!file.open(QIODevice::ReadOnly)) return false ; dataStream.setDevice(&file); while (!dataStream.atEnd()) { QString fileName; QByteArray data; //extract file name and data in order dataStream >> fileName >> data; //create any needed folder QString subfolder; for ( int i=fileName.length()-1; i>0; i--) { if ((QString(fileName.at(i)) == QString( "\\" )) || (QString(fileName.at(i)) == QString( "/" ))) { subfolder = fileName.left(i); dir.mkpath(destinationFolder+ "/" +subfolder); break ; } } QFile outFile(destinationFolder+ "/" +fileName); if (!outFile.open(QIODevice::WriteOnly)) { file.close(); return false ; } outFile.write(qUncompress(data)); outFile.close(); } file.close(); return true ; } |
Nice :-) Thanks a lot!!
ReplyDeleteWelcome.
DeleteTwo features that you missed. Hidden folders and files prefixed with "." and empty folders.
ReplyDeleteTo include hidden files change filters to:
dir.setFilter(QDir::NoDotAndDotDot | QDir::Hidden | QDir::Dirs);
dir.setFilter(QDir::NoDotAndDotDot | QDir::Hidden | QDir::Files);
To add empty folders:
In compress():
if(filesList.length() == 0) {
qDebug() << "Compressing folder: " << prefex << "/";
dataStream << QString(prefex + "/");
dataStream << " ";
}
In decompress():
if(fileName.endsWith("/") == false) {
...decompress code here...
} else {
dir.mkpath(destinationFolder + "/" + fileName);
}
Very nice, thank you so much!
ReplyDeleteDo you know an easy way to compress to ZIp format with this class?
ReplyDeleteI remember that you need to use a specific lib for zip format.
DeleteThanks for your answer. I expected that you had another answer :)
ReplyDeleteWith this class I can't export my compressed files to an external application, only to applications that have this class to uncompress! It is a pity...
By the way, do you have any suggestion to ZIP code in C++ classes/library to easily integrate with Qt?
Thank you very much!!!
ReplyDeleteThk u so !
ReplyDeleteI tried with above code, it works great, thanks to you for that ,
ReplyDeletebut if any file in the source directory is open in another application then compression fails
This comment has been removed by a blog administrator.
ReplyDeleteHi do you have limitations on folder size that you can compress? I have tried folder that have only one file, whose size is 4GB but destination file is only 1 KB in size.
ReplyDeleteI don't have and specific limitations. But for a file this big, it could be a memory issue because I simply read the file and add it. So, reading 4GB can be problematic :)
DeleteMaybe you can try changing the code to stream the data. Maybe it works