Qt Folder Compression

I needed a compression module that does not depend on anything but Qt, and I mean a module to compress a complete folder with its children. This is because I wanted the compression module to work on any platform supported by Qt with no other dependencies. So I made this modules that only uses only qCompress() & qUncompress() methods plus some logic.

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]
#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]
#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;
}

Comments