QZipReader extractAll问题
QZipReader extractAll issue
我正在使用旧的 Qt - QZipReader
class 来解压缩一些 zip 文件。它仅成功解压缩文件。当 zip 文件包含带有内容的目录时,它会显示此 QIODevice::write
问题:
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\fileszr.exe"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\aria2c.exe"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert.sh"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_config_linux"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_config_macos"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_ve_plugin"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\test5\qt-unified-windows-x86-3.1.1-online.exe"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\uup-converter-wimlib.7z"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\test\yM37erm8.jpg"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\test\yNFatJN.jpg"): device not open
代码:
#if defined(Q_OS_WIN)
# undef S_IFREG
# define S_IFREG 0100000
# ifndef S_ISDIR
# define S_ISDIR(x) ((x) & S_IFDIR) > 0
# endif
# ifndef S_ISREG
# define S_ISREG(x) ((x) & 0170000) == S_IFREG
# endif
# define S_IFLNK 020000
# define S_ISLNK(x) ((x) & S_IFLNK) > 0
# ifndef S_IRUSR
# define S_IRUSR 0400
# endif
# ifndef S_IWUSR
# define S_IWUSR 0200
# endif
# ifndef S_IXUSR
# define S_IXUSR 0100
# endif
# define S_IRGRP 0040
# define S_IWGRP 0020
# define S_IXGRP 0010
# define S_IROTH 0004
# define S_IWOTH 0002
# define S_IXOTH 0001
#endif
bool QZipReader::extractAll(const QString &destinationDir) const
{
QDir baseDir(destinationDir);
// create directories first
const QVector<FileInfo> allFiles = fileInfoList();
// for (FileInfo fi : allFiles) {
// if (fi.isDir) {
// const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
// if (!baseDir.mkpath(fi.filePath)) {
// return false;
// }
// if (!QFile::setPermissions(absPath, fi.permissions)) {
// return false;
// }
// }
// }
// // set up symlinks
// for (FileInfo fi : allFiles) {
// const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
// if (fi.isSymLink) {
// QString destination = QFile::decodeName(fileData(fi.filePath));
// if (destination.isEmpty())
// return false;
// QFileInfo linkFi(absPath);
// if (!QFile::exists(linkFi.absolutePath()))
// QDir::root().mkpath(linkFi.absolutePath());
// if (!QFile::link(destination, absPath))
// return false;
// /* cannot change permission of links
// if (!QFile::setPermissions(absPath, fi.permissions))
// return false;
// */
// }
// }
for (FileInfo fi : allFiles) {
if (!baseDir.exists()) {
baseDir.mkpath(destinationDir);
}
const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
if (fi.isDir) {
baseDir.mkpath(absPath);
}
if (fi.isFile) {
QFile f(absPath);
if (!f.isOpen()) {
f.open(QIODevice::WriteOnly);
}
f.write(fileData(fi.filePath));
f.setPermissions(fi.permissions);
f.close();
}
}
return true;
}
QVector<QZipReader::FileInfo> QZipReader::fileInfoList() const
{
d->scanFiles();
QVector<QZipReader::FileInfo> files;
for (int i = 0; i < d->fileHeaders.size(); ++i) {
QZipReader::FileInfo fi;
d->fillFileInfo(i, fi);
files.append(fi);
}
return files;
}
void QZipReaderPrivate::scanFiles()
{
if (!dirtyFileTree) {
return;
}
if (!(device->isOpen() || device->open(QIODevice::ReadOnly))) {
status = QZipReader::FileOpenError;
return;
}
if ((device->openMode() & QIODevice::ReadOnly) == 0) { // only read the index from readable files.
status = QZipReader::FileReadError;
return;
}
dirtyFileTree = false;
uchar tmp[4];
device->read((char *)tmp, 4);
if (readUInt(tmp) != 0x04034b50) {
qWarning() << "QZip: not a zip file!";
return;
}
// find EndOfDirectory header
int i = 0;
int start_of_directory = -1;
int num_dir_entries = 0;
EndOfDirectory eod;
while (start_of_directory == -1) {
const int pos = device->size() - static_cast<int>(sizeof(EndOfDirectory)) - i;
if (pos < 0 || i > 65535) {
qWarning() << "QZip: EndOfDirectory not found";
return;
}
device->seek(pos);
device->read((char *)&eod, sizeof(EndOfDirectory));
if (readUInt(eod.signature) == 0x06054b50) {
//start_of_directory = pos;
break;
}
++i;
}
// have the eod
start_of_directory = readUInt(eod.dir_start_offset);
num_dir_entries = readUShort(eod.num_dir_entries);
//qDebug() << "start_of_directory at: " << start_of_directory << " | num_dir_entries: " << num_dir_entries;
int comment_length = readUShort(eod.comment_length);
if (comment_length != i) {
qWarning() << "QZip: failed to parse zip file.";
}
comment = device->read(qMin(comment_length, i));
device->seek(start_of_directory);
for (i = 0; i < num_dir_entries; ++i) {
FileHeader header;
int read = device->read((char *) &header.h, sizeof(CentralFileHeader));
if (read < (int)sizeof(CentralFileHeader)) {
qWarning() << "QZip: Failed to read complete header, index may be incomplete";
break;
}
if (readUInt(header.h.signature) != 0x02014b50) {
qWarning() << "QZip: invalid header signature, index may be incomplete";
break;
}
int l = readUShort(header.h.file_name_length);
header.file_name = device->read(l);
if (header.file_name.length() != l) {
qWarning() << "QZip: Failed to read filename from zip index, index may be incomplete";
break;
}
l = readUShort(header.h.extra_field_length);
header.extra_field = device->read(l);
if (header.extra_field.length() != l) {
qWarning() << "QZip: Failed to read extra field in zip file, skipping file, index may be incomplete";
break;
}
l = readUShort(header.h.file_comment_length);
header.file_comment = device->read(l);
if (header.file_comment.length() != l) {
qWarning() << "QZip: Failed to read read file comment, index may be incomplete";
break;
}
qDebug() << "Found file: " << header.file_name.data();
fileHeaders.append(header);
}
}
void QZipPrivate::fillFileInfo(int index, QZipReader::FileInfo &fileInfo) const
{
FileHeader header = fileHeaders.at(index);
fileInfo.filePath = QString::fromLocal8Bit(header.file_name);
const quint32 mode = (qFromLittleEndian<quint32>(&header.h.external_file_attributes[0]) >> 16) & 0xFFFF;
fileInfo.isDir = S_ISDIR(mode);
fileInfo.isFile = S_ISREG(mode);
qDebug() << "Mode: " << mode;
qDebug() << "fileInfo.filePath: " << fileInfo.filePath << " isFile: " << fileInfo.isFile << " isDir: " << fileInfo.isDir;
fileInfo.isSymLink = S_ISLNK(mode);
fileInfo.permissions = modeToPermissions(mode);
fileInfo.size = readUInt(header.h.uncompressed_size);
fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
}
控制台应用程序:
#include <QCoreApplication>
#include <QDir>
#include <QDebug>
#include "qzipreader.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "This is a QZip test..." << endl;
QString zipFileName = "C:\Users\cobra\Downloads\22610.1_amd64_en-us_professional_00fb7ba0_convert.zip";
QString outputDirPath = "C:\Users\cobra\Downloads\Output";
QZipReader qZip(zipFileName);
bool isExtracted = qZip.extractAll(outputDirPath);
qDebug() << "isExtracted: " << isExtracted;
qZip.close();
system("Pause");
return 0;
}
我检查过 zip 文件中的所有内容都被视为文件,甚至是包含内容的目录,这导致了这个 QIODevice::write
问题。 fileInfo.isDir
returnsfalse (0)
。任何想法如何解决它?如果需要,我可以分享更多 Qt
代码。谢谢。
所以,我通过添加以下行修复了它:baseDir.mkpath(QFileInfo(absPath).absoluteDir().path());
代码:
bool QZipReader::extractAll(const QString &destinationDir) const
{
QDir baseDir(destinationDir);
if (!baseDir.exists()) {
baseDir.mkpath(destinationDir);
}
const QVector<FileInfo> allFiles = fileInfoList();
for (FileInfo fi : allFiles) {
const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
baseDir.mkpath(QFileInfo(absPath).absoluteDir().path());
if (fi.isFile) {
QFile f(absPath);
if (!f.isOpen()) {
f.open(QIODevice::WriteOnly);
}
f.write(fileData(fi.filePath));
f.setPermissions(fi.permissions);
f.close();
}
}
return true;
}
现在,它会创建所有目录并提取文件。问题已解决。谢谢。
我正在使用旧的 Qt - QZipReader
class 来解压缩一些 zip 文件。它仅成功解压缩文件。当 zip 文件包含带有内容的目录时,它会显示此 QIODevice::write
问题:
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\fileszr.exe"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\aria2c.exe"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert.sh"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_config_linux"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_config_macos"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\convert_ve_plugin"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\test5\qt-unified-windows-x86-3.1.1-online.exe"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\files\uup-converter-wimlib.7z"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\test\yM37erm8.jpg"): device not open
QIODevice::write (QFile, "C:\Users\cobra\Downloads\Output\test\yNFatJN.jpg"): device not open
代码:
#if defined(Q_OS_WIN)
# undef S_IFREG
# define S_IFREG 0100000
# ifndef S_ISDIR
# define S_ISDIR(x) ((x) & S_IFDIR) > 0
# endif
# ifndef S_ISREG
# define S_ISREG(x) ((x) & 0170000) == S_IFREG
# endif
# define S_IFLNK 020000
# define S_ISLNK(x) ((x) & S_IFLNK) > 0
# ifndef S_IRUSR
# define S_IRUSR 0400
# endif
# ifndef S_IWUSR
# define S_IWUSR 0200
# endif
# ifndef S_IXUSR
# define S_IXUSR 0100
# endif
# define S_IRGRP 0040
# define S_IWGRP 0020
# define S_IXGRP 0010
# define S_IROTH 0004
# define S_IWOTH 0002
# define S_IXOTH 0001
#endif
bool QZipReader::extractAll(const QString &destinationDir) const
{
QDir baseDir(destinationDir);
// create directories first
const QVector<FileInfo> allFiles = fileInfoList();
// for (FileInfo fi : allFiles) {
// if (fi.isDir) {
// const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
// if (!baseDir.mkpath(fi.filePath)) {
// return false;
// }
// if (!QFile::setPermissions(absPath, fi.permissions)) {
// return false;
// }
// }
// }
// // set up symlinks
// for (FileInfo fi : allFiles) {
// const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
// if (fi.isSymLink) {
// QString destination = QFile::decodeName(fileData(fi.filePath));
// if (destination.isEmpty())
// return false;
// QFileInfo linkFi(absPath);
// if (!QFile::exists(linkFi.absolutePath()))
// QDir::root().mkpath(linkFi.absolutePath());
// if (!QFile::link(destination, absPath))
// return false;
// /* cannot change permission of links
// if (!QFile::setPermissions(absPath, fi.permissions))
// return false;
// */
// }
// }
for (FileInfo fi : allFiles) {
if (!baseDir.exists()) {
baseDir.mkpath(destinationDir);
}
const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
if (fi.isDir) {
baseDir.mkpath(absPath);
}
if (fi.isFile) {
QFile f(absPath);
if (!f.isOpen()) {
f.open(QIODevice::WriteOnly);
}
f.write(fileData(fi.filePath));
f.setPermissions(fi.permissions);
f.close();
}
}
return true;
}
QVector<QZipReader::FileInfo> QZipReader::fileInfoList() const
{
d->scanFiles();
QVector<QZipReader::FileInfo> files;
for (int i = 0; i < d->fileHeaders.size(); ++i) {
QZipReader::FileInfo fi;
d->fillFileInfo(i, fi);
files.append(fi);
}
return files;
}
void QZipReaderPrivate::scanFiles()
{
if (!dirtyFileTree) {
return;
}
if (!(device->isOpen() || device->open(QIODevice::ReadOnly))) {
status = QZipReader::FileOpenError;
return;
}
if ((device->openMode() & QIODevice::ReadOnly) == 0) { // only read the index from readable files.
status = QZipReader::FileReadError;
return;
}
dirtyFileTree = false;
uchar tmp[4];
device->read((char *)tmp, 4);
if (readUInt(tmp) != 0x04034b50) {
qWarning() << "QZip: not a zip file!";
return;
}
// find EndOfDirectory header
int i = 0;
int start_of_directory = -1;
int num_dir_entries = 0;
EndOfDirectory eod;
while (start_of_directory == -1) {
const int pos = device->size() - static_cast<int>(sizeof(EndOfDirectory)) - i;
if (pos < 0 || i > 65535) {
qWarning() << "QZip: EndOfDirectory not found";
return;
}
device->seek(pos);
device->read((char *)&eod, sizeof(EndOfDirectory));
if (readUInt(eod.signature) == 0x06054b50) {
//start_of_directory = pos;
break;
}
++i;
}
// have the eod
start_of_directory = readUInt(eod.dir_start_offset);
num_dir_entries = readUShort(eod.num_dir_entries);
//qDebug() << "start_of_directory at: " << start_of_directory << " | num_dir_entries: " << num_dir_entries;
int comment_length = readUShort(eod.comment_length);
if (comment_length != i) {
qWarning() << "QZip: failed to parse zip file.";
}
comment = device->read(qMin(comment_length, i));
device->seek(start_of_directory);
for (i = 0; i < num_dir_entries; ++i) {
FileHeader header;
int read = device->read((char *) &header.h, sizeof(CentralFileHeader));
if (read < (int)sizeof(CentralFileHeader)) {
qWarning() << "QZip: Failed to read complete header, index may be incomplete";
break;
}
if (readUInt(header.h.signature) != 0x02014b50) {
qWarning() << "QZip: invalid header signature, index may be incomplete";
break;
}
int l = readUShort(header.h.file_name_length);
header.file_name = device->read(l);
if (header.file_name.length() != l) {
qWarning() << "QZip: Failed to read filename from zip index, index may be incomplete";
break;
}
l = readUShort(header.h.extra_field_length);
header.extra_field = device->read(l);
if (header.extra_field.length() != l) {
qWarning() << "QZip: Failed to read extra field in zip file, skipping file, index may be incomplete";
break;
}
l = readUShort(header.h.file_comment_length);
header.file_comment = device->read(l);
if (header.file_comment.length() != l) {
qWarning() << "QZip: Failed to read read file comment, index may be incomplete";
break;
}
qDebug() << "Found file: " << header.file_name.data();
fileHeaders.append(header);
}
}
void QZipPrivate::fillFileInfo(int index, QZipReader::FileInfo &fileInfo) const
{
FileHeader header = fileHeaders.at(index);
fileInfo.filePath = QString::fromLocal8Bit(header.file_name);
const quint32 mode = (qFromLittleEndian<quint32>(&header.h.external_file_attributes[0]) >> 16) & 0xFFFF;
fileInfo.isDir = S_ISDIR(mode);
fileInfo.isFile = S_ISREG(mode);
qDebug() << "Mode: " << mode;
qDebug() << "fileInfo.filePath: " << fileInfo.filePath << " isFile: " << fileInfo.isFile << " isDir: " << fileInfo.isDir;
fileInfo.isSymLink = S_ISLNK(mode);
fileInfo.permissions = modeToPermissions(mode);
fileInfo.size = readUInt(header.h.uncompressed_size);
fileInfo.lastModified = readMSDosDate(header.h.last_mod_file);
}
控制台应用程序:
#include <QCoreApplication>
#include <QDir>
#include <QDebug>
#include "qzipreader.h"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "This is a QZip test..." << endl;
QString zipFileName = "C:\Users\cobra\Downloads\22610.1_amd64_en-us_professional_00fb7ba0_convert.zip";
QString outputDirPath = "C:\Users\cobra\Downloads\Output";
QZipReader qZip(zipFileName);
bool isExtracted = qZip.extractAll(outputDirPath);
qDebug() << "isExtracted: " << isExtracted;
qZip.close();
system("Pause");
return 0;
}
我检查过 zip 文件中的所有内容都被视为文件,甚至是包含内容的目录,这导致了这个 QIODevice::write
问题。 fileInfo.isDir
returnsfalse (0)
。任何想法如何解决它?如果需要,我可以分享更多 Qt
代码。谢谢。
所以,我通过添加以下行修复了它:baseDir.mkpath(QFileInfo(absPath).absoluteDir().path());
代码:
bool QZipReader::extractAll(const QString &destinationDir) const
{
QDir baseDir(destinationDir);
if (!baseDir.exists()) {
baseDir.mkpath(destinationDir);
}
const QVector<FileInfo> allFiles = fileInfoList();
for (FileInfo fi : allFiles) {
const QString absPath = QDir::toNativeSeparators(QString("%1/%2").arg(destinationDir, fi.filePath));
baseDir.mkpath(QFileInfo(absPath).absoluteDir().path());
if (fi.isFile) {
QFile f(absPath);
if (!f.isOpen()) {
f.open(QIODevice::WriteOnly);
}
f.write(fileData(fi.filePath));
f.setPermissions(fi.permissions);
f.close();
}
}
return true;
}
现在,它会创建所有目录并提取文件。问题已解决。谢谢。