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());
}
}
include(thirdParty/quazip/quazip.pri)
and LIBS += -lz
to import QuaZip to your Qt project. –
Rasia 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();
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;
}
}
© 2022 - 2024 — McMap. All rights reserved.