开发者

Zipping a folder/file using Qt

开发者 https://www.devze.com 2022-12-26 06:10 出处:网络
I would like to know if there is any class in Qt which can zip a folder or file. 开发者_如何转开发I used QProcess to compress, it got compressed but I am unable to uncompress it using a normal zip too

I would like to know if there is any class in Qt which can zip a folder or file. 开发者_如何转开发I used QProcess to compress, it got compressed but I am unable to uncompress it using a normal zip tool. Can anyone let me know how can we compress a folder/file using Qt api classes?


A few years ago I had such a issue, and here is my solution:

1). get QuaZip (here is the link text)

2). include quazip sources to your project file

Headers:

HEADERS += src/quazip/crypt.h \
           src/quazip/ioapi.h \
           src/quazip/quazip.h \
           src/quazip/quazipfile.h \
           src/quazip/quazipfileinfo.h \
           src/quazip/quazipnewinfo.h \
           src/quazip/unzip.h \
           src/quazip/zip.h \
           ...

Sources:

SOURCES += src/quazip/ioapi.c \
           src/quazip/quazip.cpp \
           src/quazip/quazipfile.cpp \
           src/quazip/quazipnewinfo.cpp \
           src/quazip/unzip.c \
           src/quazip/zip.c
           ...

3). add headers

#include "quazip/quazip.h"
#include "quazip/quazipfile.h"

4). use extract function:

static bool extract(const QString & filePath, const QString & extDirPath, const QString & singleFileName = QString("")) {

QuaZip zip(filePath);

if (!zip.open(QuaZip::mdUnzip)) {
    qWarning("testRead(): zip.open(): %d", zip.getZipError());
    return false;
}

zip.setFileNameCodec("IBM866");

qWarning("%d entries\n", zip.getEntriesCount());
qWarning("Global comment: %s\n", zip.getComment().toLocal8Bit().constData());

QuaZipFileInfo info;

QuaZipFile file(&zip);

QFile out;
QString name;
char c;
for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile()) {

    if (!zip.getCurrentFileInfo(&info)) {
        qWarning("testRead(): getCurrentFileInfo(): %d\n", zip.getZipError());
        return false;
    }

    if (!singleFileName.isEmpty())
        if (!info.name.contains(singleFileName))
            continue;

    if (!file.open(QIODevice::ReadOnly)) {
        qWarning("testRead(): file.open(): %d", file.getZipError());
        return false;
    }

    name = QString("%1/%2").arg(extDirPath).arg(file.getActualFileName());

    if (file.getZipError() != UNZ_OK) {
        qWarning("testRead(): file.getFileName(): %d", file.getZipError());
        return false;
    }

    //out.setFileName("out/" + name);
    out.setFileName(name);

    // this will fail if "name" contains subdirectories, but we don't mind that
    out.open(QIODevice::WriteOnly);
    // Slow like hell (on GNU/Linux at least), but it is not my fault.
    // Not ZIP/UNZIP package's fault either.
    // The slowest thing here is out.putChar(c).
    while (file.getChar(&c)) out.putChar(c);

    out.close();

    if (file.getZipError() != UNZ_OK) {
        qWarning("testRead(): file.getFileName(): %d", file.getZipError());
        return false;
    }

    if (!file.atEnd()) {
        qWarning("testRead(): read all but not EOF");
        return false;
    }

    file.close();

    if (file.getZipError() != UNZ_OK) {
        qWarning("testRead(): file.close(): %d", file.getZipError());
        return false;
    }
}

zip.close();

if (zip.getZipError() != UNZ_OK) {
    qWarning("testRead(): zip.close(): %d", zip.getZipError());
    return false;
}

return true;
}

and archive function:

static bool archive(const QString & filePath, const QDir & dir, const QString & comment = QString("")) {

QuaZip zip(filePath);
zip.setFileNameCodec("IBM866");

if (!zip.open(QuaZip::mdCreate)) {
    myMessageOutput(true, QtDebugMsg, QString("testCreate(): zip.open(): %1").arg(zip.getZipError()));
    return false;
}

if (!dir.exists()) {
    myMessageOutput(true, QtDebugMsg, QString("dir.exists(%1)=FALSE").arg(dir.absolutePath()));
    return false;
}

QFile inFile;

// Получаем список файлов и папок рекурсивно
QStringList sl;
recurseAddDir(dir, sl);

// Создаем массив состоящий из QFileInfo объектов
QFileInfoList files;
foreach (QString fn, sl) files << QFileInfo(fn);

QuaZipFile outFile(&zip);

char c;
foreach(QFileInfo fileInfo, files) {

    if (!fileInfo.isFile())
        continue;

    // Если файл в поддиректории, то добавляем имя этой поддиректории к именам файлов
    // например: fileInfo.filePath() = "D:\Work\Sources\SAGO\svn\sago\Release\tmp_DOCSWIN\Folder\123.opn"
    // тогда после удаления части строки fileNameWithSubFolders будет равен "Folder\123.opn" и т.д.
    QString fileNameWithRelativePath = fileInfo.filePath().remove(0, dir.absolutePath().length() + 1);

    inFile.setFileName(fileInfo.filePath());

    if (!inFile.open(QIODevice::ReadOnly)) {
        myMessageOutput(true, QtDebugMsg, QString("testCreate(): inFile.open(): %1").arg(inFile.errorString().toLocal8Bit().constData()));
        return false;
    }

    if (!outFile.open(QIODevice::WriteOnly, QuaZipNewInfo(fileNameWithRelativePath, fileInfo.filePath()))) {
        myMessageOutput(true, QtDebugMsg, QString("testCreate(): outFile.open(): %1").arg(outFile.getZipError()));
        return false;
    }

    while (inFile.getChar(&c) && outFile.putChar(c));

    if (outFile.getZipError() != UNZ_OK) {
        myMessageOutput(true, QtDebugMsg, QString("testCreate(): outFile.putChar(): %1").arg(outFile.getZipError()));
        return false;
    }

    outFile.close();

    if (outFile.getZipError() != UNZ_OK) {
        myMessageOutput(true, QtDebugMsg, QString("testCreate(): outFile.close(): %1").arg(outFile.getZipError()));
        return false;
    }

    inFile.close();
}

// + комментарий
if (!comment.isEmpty())
    zip.setComment(comment);

zip.close();

if (zip.getZipError() != 0) {
    myMessageOutput(true, QtDebugMsg, QString("testCreate(): zip.close(): %1").arg(zip.getZipError()));
    return false;
}

return true;
}

5). enjoy ;)

UPDATE: for CapDroid.

/* Рекурсивно ищет все файлы в директории \a и добавляет в список \b */
static void recurseAddDir(QDir d, QStringList & list) {

    QStringList qsl = d.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files);

    foreach (QString file, qsl) {

        QFileInfo finfo(QString("%1/%2").arg(d.path()).arg(file));

        if (finfo.isSymLink())
            return;

        if (finfo.isDir()) {

            QString dirname = finfo.fileName();
            QDir sd(finfo.filePath());

            recurseAddDir(sd, list);

        } else
            list << QDir::toNativeSeparators(finfo.filePath());
    }
}


I don't think you can. As far as I know qcompress and quncompress only provide compressing of streams etc. This means they will not create the headers needed for a real zipfile (which also say which files are in the file).

However there is an open source Qt library called QuaZip which uses zlib (comes with qt) and provides just that.


I'm using Qt 5.12 version.

In pro file, add "QT += gui-private".

In the cpp file, example:

#include "QtGui/private/qzipreader_p.h"
#include "QtGui/private/qzipwriter_p.h"

......


QFileInfoList list = getFileList(zipPath);//zipPath
QZipWriter writer(zipFile);
if(list.size()<=0){
    qDebug()<<"there is no file to zip, please check it";
    return false;
}
//
for(int i=0;i != list.size(); i++){
    QString filename=list.at(i).filePath();
    qDebug()<<"filename:"<<filename.mid(pos+1);
    QFile file(filename);
    if(file.exists()){
        file.open(QIODevice::ReadOnly);
        writer.addFile(filename.mid(pos+1), file.readAll());
        file.close();
    }
    else{
        qDebug()<<"file not exist:"<<filename;
    }
}
writer.close();
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号