Qt: QuaZip to extract file and show its progress in QProgressDialog

3.2k views Asked by At

How could I use QuaZip to extract a .zip file and show its extraction progress in a QProgressDialog?

I've tried an example from this question1 (and also this question2) without success. Because I need to unzip .zip files (not .gz files) and that code shows % of progress but not unzip the files. And even that, I don't know how to show that % in a QProgressDialog.

I've been able to extract .zip file using:

JlCompress::extractDir("C:/test/test.zip", "C:/test/");

However, that is not enought for my goal, because I need to show that extraction progress in a QProgressDialog in real time...

This is my code:

QString fileName = "C:/test/firefox-29.0.1.gz"; //I need to unzip .zip files
qDebug() << "Opened";
progressUnzip->setWindowTitle(tr("Unzip Manager"));
progressUnzip->setLabelText(tr("Unzipping %1. \nThis can take a long time to complete").arg(fileName));
progressUnzip->setAttribute(Qt::WA_DeleteOnClose);

QFile file(fileName);
file.open(QFile::ReadOnly);
QuaGzipFile gzip;
gzip.open(file.handle(), QuaGzipFile::ReadOnly);

progressUnzip->show();

while(true) {
    QByteArray buf = gzip.read(1000);
    //process buf
    if (buf.isEmpty()) { break; }
    QFile temp_file_object;
    temp_file_object.open(file.handle(), QFile::ReadOnly);
    double progress = 100.0 * temp_file_object.pos() / file.size();
    updateUnzipProgress(temp_file_object.pos(), file.size());
    qDebug() << qRound(progress) << "%";
}
unzipFinished();

qDebug() << "Finish";

Where:

void MainWindow::updateUnzipProgress(qint64 bytesRead, qint64 totalBytes)
{
    qDebug() << bytesRead << "/" << totalBytes;
    qint64 th = 1;
    if (totalBytes >= 100000000)
    {
        th = 1000;
    }
    progressUnzip->setMaximum(totalBytes/th);
    progressUnzip->setValue(bytesRead/th);
}

// When unzip finished or canceled, this will be called
void MainWindow::unzipFinished()
{
    qDebug() << "Unzip finished.";
    progressUnzip->hide();
}

In this code, QProgressDialog doesn't show any progress bar and at the end the file is not unzipped.

Any idea?

Thanks for your help,

1

There are 1 answers

1
hank On

I'm not going to write the whole code for you, but I can give you some hints to help you solve the problem.

QuaZIP library does not provide any Qt signals about the extraction progress, and that means that you should implement it yourself.

First, take a look at JlCompress::extractDir function implementation to see how it works. The source code can be found here. The function creates a QuaZip object which describes the zip archive you want to extract. Then it iterates over the files in the archive. On every iteration it creates a QuaZipFile object which describes a compressed file in the archive and then writes (=extracts) its data to a new file.

This is the copy function:

static bool copyData(QIODevice &inFile, QIODevice &outFile)
{
    while (!inFile.atEnd()) {
        char buf[4096];
        qint64 readLen = inFile.read(buf, 4096);
        if (readLen <= 0)
            return false;
        if (outFile.write(buf, readLen) != readLen)
            return false;
    }
    return true;
}

inFile is the compressed (QuaZipFile) file and outFile is a new file where the compressed data is extracted to.

Now you should understand the underlying logic.

To add signals about extraction progress, you can can copy the JlCompress::extractDir source code to some wrapper class and make some changes.

While iterating over the files in the archive, you can get information about them using QuaZipFile::getFileInfo. That information contains uncompressed file size. Now go back to the copyData function. You know how many bytes you have written and you know the expected file size. That means you can calculate the single file extraction progress. Also you can get total files count and their uncompressed sizes using QuaZip::getFileInfoList64. That will let you calculate the whole extraction progress too.