c++ - 如何从分离的 QProcess 中读取标准输出/标准错误

标签 c++ multithreading qt

我是 Qt 的初学者。我需要通过桌面应用程序中的按钮调用命令行程序。该程序下载 YouTube 视频。我还需要从中读取标准错误。我写了下面的代码:

void YoutubeDL::on_downloadButton_clicked()
{
    [...]

    QProcess p;
    p.startDetached("youtube-dl -f " + get + " " + ui->urlBox->text());
    QString perr = p.readAllStandardError();
    if (perr.length())
        ui->descBox->setText("Error during download.\n" + perr);
    else
        ui->descBox->setText("Download completed!");
}

但是不会发生 stderr 读取。

另一方面,如果我使用非分离的 p.start() 然后使用 waitForFinished(-1) 那么我可以读取 stderr,但是 GUI 卡住直到下载完成。

如何解决这个问题?

一个相关问题:我还想要一些能够实时读取下载过程输出的方法,以便我可以在 GUI 中显示它。 youtube-dl 给出这样的进度报告:

[download]   0.0% of 2.00MiB at 173.22KiB/s ETA 00:12
[download]   0.1% of 2.00MiB at 105.01KiB/s ETA 00:19
[download]   0.3% of 2.00MiB at 96.86KiB/s ETA 00:21
[download]   0.7% of 2.00MiB at 105.23KiB/s ETA 00:19
[download]   1.5% of 2.00MiB at 100.29KiB/s ETA 00:20
...

我希望能够在它们生成时阅读它们。

最佳答案

由于问题的性质,以上所有答案都不正确。 @aakashjain 要求一个分离 过程。你们的建议仅在启动过程仍然附加的情况下才有效。

QProcess p
p.startDetached(...)

相同
QProcess::startDetached(...)

QProcess::startDetached() 是一个静态方法,它不是任何对象的一部分或返回一个对象。一旦您调用此方法并成功,该进程将不再以任何方式附加到生成它的进程(您的应用程序)。

我建议你先看看 official documentation on this method然后阅读更多关于 interprocess communication 的信息以及如何将一个进程的输出通过管道传输到另一个进程(在本例中是分离进程到终端)。

我什至在 PyQt4 中使用 QProcess::startDetached() 时偶然发现了基本控制的问题,在那里我完全按照@DmitrySokolov 的建议做了。令我惊讶的是,状态始终为零,无法使用 QProcess 非静态方法设置或检索任何内容。经过一番挖掘和询问后,我得到的正是我在回答开头所写的内容——如果您使用 QProcess::startDetached(),则必须通过系统工具(例如 kill 命令、管道等),因为您没有实际可以使用的对象。

QProcess::startDetached() 提供了两个重要的返回值:

  • 方法本身的返回值 - 一个 bool 值,它告诉您进程启动是成功 (==true) 还是失败 (==false)
  • 函数的 qint64 * pid 指针参数 - 如果进程已成功启动,pid 将包含分离进程的 PID(进程标识符)

您可以使用此 PID 以您喜欢的任何方式与进程交互(进程本身当然允许您这样做;))- 您可以终止它、通过管道传输其输出、使其休眠等。

现在回到你的问题。这里有三种解决方案:

  • 启动子进程 - 该进程将包含在 QProcess 对象中,您可以按照@DmitrySokolov 的描述与其进行交互。然而,这将阻止您处理 UI 的主线程,直到子进程完成其任务并停止(主线程在您的 Qt 应用程序的进程内运行)。我怀疑您希望您的 UI 卡住(正如您通过自己的实验注意到的那样),尤其是因为我们正在谈论下载可能包含大量视频数据的内容...
  • 开始一个分离的过程——我在这个解决方案列表之前已经描述过的。然而,它需要对进程间通信有更多的了解。如果您愿意并想花一些时间研究这个主题(我只能鼓励您这样做!),那就去做吧
  • 在其中启动一个线程和一个子进程 - 您不仅可以真正巧妙地控制下载任务,还可以通过插槽和信号向 UI 提供很好的反馈,这将改善用户体验很多。这是此类任务使用最广泛的方法,我还可以在您的评论中看到您想在 ui->descBox 中输出进度(您还可以添加 QProgressbar 以使输出更用户化-友好并在后台执行 stdout/stderr 操作,仅供您查看)。老实说,我还没有对此进行测试,但它应该有效。

关于c++ - 如何从分离的 QProcess 中读取标准输出/标准错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22574867/

相关文章:

c++ - QLayout 和 QWidget 之间的转换

c++ - 如何将 lambda 函数传递给具有模板类的类的实例化

c++ - Visual Studio 编译器错误 : a call to a delegating constructor shall be the only member-initializer

c# - 线程/线程池或后台 worker

javascript - 类型转换 : Component to RadioButtonStyle

c++ - 在类中定义数组的方法和字段

c# - 如何实现多线程并行执行多个任务?

c - hp load runner 中的多线程

c++ - 为什么 windows 任务栏自定义任务列表在 windows 10 上没有 pin 时不起作用?

python - pyqt Qtreewidget 标题单击不起作用