使用 Qt 压缩文件夹/文件

发布于 2024-08-27 17:50:29 字数 103 浏览 4 评论 0原文

我想知道 Qt 中是否有任何可以压缩文件夹或文件的类。我使用 QProcess 进行压缩,它被压缩了,但我无法使用普通的压缩工具解压缩它。谁能告诉我如何使用 Qt api 类压缩文件夹/文件?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秋叶绚丽 2024-09-03 17:50:29

几年前我遇到过这样的问题,这是我的解决方案:

1)。获取 QuaZip(这里是链接文本

2)。将 quazip 源代码包含到您的项目文件

标题:

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 += 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)。添加标题

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

4).使用提取功能:

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

和存档功能:

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)。享受;)

更新:对于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());
    }
}

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());
    }
}
冰之心 2024-09-03 17:50:29

我使用的是 Qt 5.12 版本。

在 pro 文件中,添加“QT += gui-private”。

在cpp文件中,例如:

#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();

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();
高冷爸爸 2024-09-03 17:50:29

我认为你不能。据我所知,qcompress 和 quncompress 仅提供流的压缩等。这意味着它们不会创建真正的 zip 文件所需的标头(也说明文件中包含哪些文件)。

然而,有一个名为 QuaZip 的开源 Qt 库,它使用 zlib(随 qt 一起提供)并提供该库。

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.

风渺 2024-09-03 17:50:29

https://libzip.org/license/ 拥有 BSD 许可证,您可以在任何地方使用它

示例(在 Linux 上)
在 .pro 文件中:

HEADERS +=  /usr/include/zip.h

LIBS += -L/usr/lib/x86_64-linux-gnu/ -lzip

INCLUDEPATH += /usr/lib/x86_64-linux-gnu/libzip/include headers

zip 文件的功能:

int PutFileIntoZip(const QString &filePath)
{
    QFile regFile(filePath);
    Q_ASSERT(regFile.exists());
    const bool canOpenRegFile=regFile.open(QIODevice::ReadOnly);
    if(canOpenRegFile)
    {
        QString fileNameExpansion=filePath.section(QDir::separator(),-1,-1);
        const QStringRef fileName(&fileNameExpansion, 0, fileNameExpansion.length()-4);//22222.bin -> 22222
        int errorFlagCreateZip = 0;
        const QString zipPath=QDir::homePath()+QDir::separator()+fileName + ".zip";
        zip*const  zipHandle = zip_open(zipPath.toLatin1().constData(), ZIP_CREATE, &errorFlagCreateZip);
        if (ZIP_ER_OK==errorFlagCreateZip)
        {
            FILE* const fileC = fdopen(regFile.handle(), "r");
            zip_source* const  source = zip_source_filep(zipHandle, fileC, 0, regFile.size());
            if (source!=nullptr)
            {
                const zip_int64_t result = zip_file_add(zipHandle, fileNameExpansion.toLatin1().constData(), source, ZIP_FL_OVERWRITE);
                if (result>=0)
                {
                    zip_set_file_compression(zipHandle, result, ZIP_CM_DEFLATE64, 0);
                    qDebug()<< "Done";
                }
                else
                {
                    zip_source_free(source);
                }
            }
            int result = zip_close(zipHandle);
            fclose(fileC);
            regFile.close();
            return result;
        }
        else
        {
            zip_error_t error;
            zip_error_init_with_code(&error, errorFlagCreateZip);
            const int zipCreationErrorCode = zip_error_code_zip(&error);
            regFile.close();
            return zipCreationErrorCode;
        }
    }
    else
    {
        qDebug()<< regFile.errorString();
        return -1;
    }
}

https://libzip.org/license/ has BSD licence you can use it anywhere

Example (On Linux)
In .pro file:

HEADERS +=  /usr/include/zip.h

LIBS += -L/usr/lib/x86_64-linux-gnu/ -lzip

INCLUDEPATH += /usr/lib/x86_64-linux-gnu/libzip/include headers

Function that zip file:

int PutFileIntoZip(const QString &filePath)
{
    QFile regFile(filePath);
    Q_ASSERT(regFile.exists());
    const bool canOpenRegFile=regFile.open(QIODevice::ReadOnly);
    if(canOpenRegFile)
    {
        QString fileNameExpansion=filePath.section(QDir::separator(),-1,-1);
        const QStringRef fileName(&fileNameExpansion, 0, fileNameExpansion.length()-4);//22222.bin -> 22222
        int errorFlagCreateZip = 0;
        const QString zipPath=QDir::homePath()+QDir::separator()+fileName + ".zip";
        zip*const  zipHandle = zip_open(zipPath.toLatin1().constData(), ZIP_CREATE, &errorFlagCreateZip);
        if (ZIP_ER_OK==errorFlagCreateZip)
        {
            FILE* const fileC = fdopen(regFile.handle(), "r");
            zip_source* const  source = zip_source_filep(zipHandle, fileC, 0, regFile.size());
            if (source!=nullptr)
            {
                const zip_int64_t result = zip_file_add(zipHandle, fileNameExpansion.toLatin1().constData(), source, ZIP_FL_OVERWRITE);
                if (result>=0)
                {
                    zip_set_file_compression(zipHandle, result, ZIP_CM_DEFLATE64, 0);
                    qDebug()<< "Done";
                }
                else
                {
                    zip_source_free(source);
                }
            }
            int result = zip_close(zipHandle);
            fclose(fileC);
            regFile.close();
            return result;
        }
        else
        {
            zip_error_t error;
            zip_error_init_with_code(&error, errorFlagCreateZip);
            const int zipCreationErrorCode = zip_error_code_zip(&error);
            regFile.close();
            return zipCreationErrorCode;
        }
    }
    else
    {
        qDebug()<< regFile.errorString();
        return -1;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文