QProcess 使用 7zip 作为子进程提取文件
QProcess to extract file using 7zip as subprocess
我在使用 C++ 和 Qt 的应用程序中有一个用例(windows 10)。该应用程序使用 7zip.exe 作为子进程来解压缩选定文件夹中的文件。我需要使用 QProcess 来提取文件。
我想出的代码如下所示。
MainWindow.h
QStringList zipFiles;
MainWindow.cpp
void MainWindow::on_browseButton_clicked()
{
directory = QFileDialog::getExistingDirectory(this);
if(recursiveOperation){
QDirIterator it(directory.canonicalPath(), QStringList() << "*.zip" << "*.7z", QDir::Files, QDirIterator::Subdirectories);
ui->outputLogResultList->addItem("File selected to uncompress");
ui->outputLogResultList->addItem("-----------------------------");
while (it.hasNext()){
QString file = it.next();
ui->outputLogResultList->addItem(file);
zipFilesWithRecursion.append(file);
}
}else{
zipFilesWithoutRecursion = directory.entryList(QStringList() << "*.zip"<< "*.7z", QDir::Files);
qDebug() << zipFilesWithoutRecursion;
foreach(QString filename4, zipFilesWithoutRecursion) {
qDebug() << "inside loop";
zipFilesWithCompletePath.append( QString(directory.canonicalPath()+"/%1").arg(filename4));
}
qDebug() << "without recursion";
qDebug() << zipFilesWithCompletePath;
}
}
void MainWindow::unZipFile()
{
int numberOfFiles;
if(recursiveOperation){
numberOfFiles = zipFilesWithRecursion.size();
foreach(QString filename3, zipFilesWithRecursion) {
QStringList queryArguments;
queryArguments << "x";
qDebug() << filename3;
queryArguments <<""""+ filename3+ """";
queryArguments << "-o"+directory.canonicalPath()+"/output"+QString().setNum(numberOfFiles);
qDebug() << queryArguments;
unZip.setWorkingDirectory(QCoreApplication::applicationDirPath());
unZip.start("7za.exe", queryArguments);
numberOfFiles--;
}
numberOfFiles = 0;
}else{
numberOfFiles = zipFilesWithCompletePath.size();
foreach(QString filename3, zipFilesWithCompletePath) {
QStringList queryArguments;
queryArguments << "x";
qDebug() << filename3;
queryArguments <<""""+ filename3+ """";
queryArguments << "-o"+directory.canonicalPath()+"/output"+QString().setNum(numberOfFiles);
qDebug() << queryArguments;
unZip.setWorkingDirectory(QCoreApplication::applicationDirPath());
unZip.start("7za.exe", queryArguments);
numberOfFiles--;
}
numberOfFiles = 0;
}
}
代码 运行 正确,但在处理第一个文件后,它不会处理任何其他文件并显示状态“QProcess::start:进程已经 运行ning”
输出段如下
Warning: QT_DEVICE_PIXEL_RATIO is deprecated. Instead use:
QT_AUTO_SCREEN_SCALE_FACTOR to enable platform plugin controlled per-screen factors.
QT_SCREEN_SCALE_FACTORS to set per-screen DPI.
QT_SCALE_FACTOR to set the application global scale factor.
("SemiFinal.zip", "temata_vskp_-_podklady_pro_zadani_vskp(10).zip")
inside loop
inside loop
without recursion
("F:/taskPractiseDirectoryForQt/SemiFinal.zip", "F:/taskPractiseDirectoryForQt/temata_vskp_-_podklady_pro_zadani_vskp(10).zip")
"F:/taskPractiseDirectoryForQt/SemiFinal.zip"
("x", "F:/taskPractiseDirectoryForQt/SemiFinal.zip", "-oF:/taskPractiseDirectoryForQt/output2")
"F:/taskPractiseDirectoryForQt/temata_vskp_-_podklady_pro_zadani_vskp(10).zip"
("x", "F:/taskPractiseDirectoryForQt/temata_vskp_-_podklady_pro_zadani_vskp(10).zip", "-oF:/taskPractiseDirectoryForQt/output1")
QProcess::start: Process is already running
该文件夹有 2 个 .zip 文件,我的问题是为什么第二个文件没有得到处理。
您必须等待您的 QProcess(解压缩)完成,然后才能处理下一个文件或在 void MainWindow::unZipFile()
方法中以周期 foreach(QString filename3, zipFilesWithCompletePath)
为每个文件创建 QProcess 实例以同时处理它们。
如果您尝试等待 unZip.waitForFinished()
,您的应用程序将在这段时间内没有响应,因为它的主线程将被挂起,直到进程完成。
如果你想并发处理文件, QProcess 实例应该在堆中创建,例如auto unZipFileProcess = new QProcess(this);
并且您需要编写一些代码来控制启动的进程并在关闭应用程序之前等待它们全部完成,因为在这种情况下所有进程都会被它们的析构函数中断和终止。要控制进程状态,连接到 QProcess 实例信号是正确的 - errorOccurred
和 finished
。此外,这些信号应连接到 QProcess 的 deleteLater
槽以避免内存增长。此时您根本不需要 unZip
静态变量或成员变量(我不知道它是如何声明的)。
换句话说,如果您不需要跟踪文件处理(等待完成、报告进程错误等),您可以使用静态 QProcess::startDetached
方法以分离方式启动进程,并且根本不创建任何 QProcess 实例。因此您不需要控制它们并将它们与您的应用程序生命周期同步。
而且您确实需要重新设计 MainWindow::unZipFile()
方法以避免代码重复。
正如@Alexey 建议的那样,我使用了
unZip.waitForFinished(3000);
在循环结束之前对我有用。
我在使用 C++ 和 Qt 的应用程序中有一个用例(windows 10)。该应用程序使用 7zip.exe 作为子进程来解压缩选定文件夹中的文件。我需要使用 QProcess 来提取文件。
我想出的代码如下所示。
MainWindow.h
QStringList zipFiles;
MainWindow.cpp
void MainWindow::on_browseButton_clicked()
{
directory = QFileDialog::getExistingDirectory(this);
if(recursiveOperation){
QDirIterator it(directory.canonicalPath(), QStringList() << "*.zip" << "*.7z", QDir::Files, QDirIterator::Subdirectories);
ui->outputLogResultList->addItem("File selected to uncompress");
ui->outputLogResultList->addItem("-----------------------------");
while (it.hasNext()){
QString file = it.next();
ui->outputLogResultList->addItem(file);
zipFilesWithRecursion.append(file);
}
}else{
zipFilesWithoutRecursion = directory.entryList(QStringList() << "*.zip"<< "*.7z", QDir::Files);
qDebug() << zipFilesWithoutRecursion;
foreach(QString filename4, zipFilesWithoutRecursion) {
qDebug() << "inside loop";
zipFilesWithCompletePath.append( QString(directory.canonicalPath()+"/%1").arg(filename4));
}
qDebug() << "without recursion";
qDebug() << zipFilesWithCompletePath;
}
}
void MainWindow::unZipFile()
{
int numberOfFiles;
if(recursiveOperation){
numberOfFiles = zipFilesWithRecursion.size();
foreach(QString filename3, zipFilesWithRecursion) {
QStringList queryArguments;
queryArguments << "x";
qDebug() << filename3;
queryArguments <<""""+ filename3+ """";
queryArguments << "-o"+directory.canonicalPath()+"/output"+QString().setNum(numberOfFiles);
qDebug() << queryArguments;
unZip.setWorkingDirectory(QCoreApplication::applicationDirPath());
unZip.start("7za.exe", queryArguments);
numberOfFiles--;
}
numberOfFiles = 0;
}else{
numberOfFiles = zipFilesWithCompletePath.size();
foreach(QString filename3, zipFilesWithCompletePath) {
QStringList queryArguments;
queryArguments << "x";
qDebug() << filename3;
queryArguments <<""""+ filename3+ """";
queryArguments << "-o"+directory.canonicalPath()+"/output"+QString().setNum(numberOfFiles);
qDebug() << queryArguments;
unZip.setWorkingDirectory(QCoreApplication::applicationDirPath());
unZip.start("7za.exe", queryArguments);
numberOfFiles--;
}
numberOfFiles = 0;
}
}
代码 运行 正确,但在处理第一个文件后,它不会处理任何其他文件并显示状态“QProcess::start:进程已经 运行ning” 输出段如下
Warning: QT_DEVICE_PIXEL_RATIO is deprecated. Instead use:
QT_AUTO_SCREEN_SCALE_FACTOR to enable platform plugin controlled per-screen factors.
QT_SCREEN_SCALE_FACTORS to set per-screen DPI.
QT_SCALE_FACTOR to set the application global scale factor.
("SemiFinal.zip", "temata_vskp_-_podklady_pro_zadani_vskp(10).zip")
inside loop
inside loop
without recursion
("F:/taskPractiseDirectoryForQt/SemiFinal.zip", "F:/taskPractiseDirectoryForQt/temata_vskp_-_podklady_pro_zadani_vskp(10).zip")
"F:/taskPractiseDirectoryForQt/SemiFinal.zip"
("x", "F:/taskPractiseDirectoryForQt/SemiFinal.zip", "-oF:/taskPractiseDirectoryForQt/output2")
"F:/taskPractiseDirectoryForQt/temata_vskp_-_podklady_pro_zadani_vskp(10).zip"
("x", "F:/taskPractiseDirectoryForQt/temata_vskp_-_podklady_pro_zadani_vskp(10).zip", "-oF:/taskPractiseDirectoryForQt/output1")
QProcess::start: Process is already running
该文件夹有 2 个 .zip 文件,我的问题是为什么第二个文件没有得到处理。
您必须等待您的 QProcess(解压缩)完成,然后才能处理下一个文件或在 void MainWindow::unZipFile()
方法中以周期 foreach(QString filename3, zipFilesWithCompletePath)
为每个文件创建 QProcess 实例以同时处理它们。
如果您尝试等待 unZip.waitForFinished()
,您的应用程序将在这段时间内没有响应,因为它的主线程将被挂起,直到进程完成。
如果你想并发处理文件, QProcess 实例应该在堆中创建,例如auto unZipFileProcess = new QProcess(this);
并且您需要编写一些代码来控制启动的进程并在关闭应用程序之前等待它们全部完成,因为在这种情况下所有进程都会被它们的析构函数中断和终止。要控制进程状态,连接到 QProcess 实例信号是正确的 - errorOccurred
和 finished
。此外,这些信号应连接到 QProcess 的 deleteLater
槽以避免内存增长。此时您根本不需要 unZip
静态变量或成员变量(我不知道它是如何声明的)。
换句话说,如果您不需要跟踪文件处理(等待完成、报告进程错误等),您可以使用静态 QProcess::startDetached
方法以分离方式启动进程,并且根本不创建任何 QProcess 实例。因此您不需要控制它们并将它们与您的应用程序生命周期同步。
而且您确实需要重新设计 MainWindow::unZipFile()
方法以避免代码重复。
正如@Alexey 建议的那样,我使用了
unZip.waitForFinished(3000);
在循环结束之前对我有用。