Home Articles

QProcess问题,输出过程

Asked
Viewed 1394 times
4

我想弄清楚QProcess的用途 . 我没有运气地看着Qt doc .
http://doc.qt.io/qt-4.8/qprocess.html

EXAMPLES OF PROBLEM.

Example 1: 代码bellow工作 .

#include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QByteArray>
#include <QProcess>    

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTextStream qout(stdout);    

    QProcess cmd;

    cmd.start("cmd");
    if (!cmd.waitForStarted())  {
        return false;
    }

    cmd.waitForReadyRead();
    QByteArray result = cmd.readAll();
    //qout << result.data() << endl;   //console junk captured, don't show. 

    //My test command
    cmd.write("echo hello");
    cmd.write("\n");

    //Capture my result
    cmd.waitForReadyRead();
    //This is my command shown by cmd, I don't show it, capture & discard it.
    result = cmd.readLine();
    //Read result of my command ("hello") and the rest of output like cur dir.   
    result = cmd.readAll();    
    qout << result.data();

    qout << "\n\n---End, bye----" << endl;
    return a.exec();
}

上面代码的 output

你好F:\ Dev_Qt \ expControllingExtConsoleApps-build-desktop>

---结束,再见----

问题是,如果我尝试通过Qprocess和cmd控制台以这种方式使用ipconfig或7zip,我将无法看到ipconfig或7zip的任何输出 . 我不知道是否有任何事情已经完成,如果有什么事情已经完成,那么为什么我看不到输出?代码如下所示 .

Example 2: 不起作用 . 无法使用ipconfig .

#include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QByteArray>
#include <QString>
#include <QProcess>    

int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
   QTextStream qout(stdout);

   QProcess cmd2;
    cmd2.setWorkingDirectory("C:/Program Files/7-Zip");   //not needed in this example.
    cmd2.setReadChannel(QProcess::StandardOutput);
    cmd2.setProcessChannelMode(QProcess::MergedChannels);

    cmd2.start("cmd");
    if (!cmd2.waitForStarted())
    {
        qout << "Error: Could not start!" << endl;
        return false;
    }

    cmd2.waitForReadyRead();
    QByteArray result = cmd2.readAll();
    qout << result.data() << endl;      //Console version info, etc.

    //My command
    cmd2.write("ipconfig");
    cmd2.write("\n");

    //Capture output of ipconfig command
    //DOES NOT WORK!!
    cmd2.waitForReadyRead();
    while (! cmd2.atEnd())
    {
        result = cmd2.readLine();
        qout << result;
        result.clear();
    }
    qout << endl;

    qout << "\n\n---end----" << endl;
    return a.exec();

}

Output 如下,它缺少ipconfig连接信息结果 . 根本没有捕获ipconfig的输出 .

Microsoft Windows XP [版本5.1.2600](C)版权所有1985-2001 Microsoft Corp. C:\ Program Files \ 7-Zip> ipconfig --- end ----

应该更像这样(使用ipconfig结果) .

Microsoft Windows XP [版本5.1.2600](C)版权所有1985-2001 Microsoft Corp. C:\ Documents and Settings \ noname> ipconfig Windows IP配置以太网适配器本地连接:特定于连接的DNS后缀 . :
IP地址 . . . . . . . . . . . . :192.172.148.135
子网掩码 . . . . . . . . . . . :255.255.255.0
默认网关 . . . . . . . . . :192.172.148.177
C:\ Documents and Settings \ noname>

显然输出应该比上面有点差异,但连接信息应该是“ipconfig”的输出应该被捕获 . 以同样的方式,如果我尝试通过cmd控制台使用7zip ...我无法看到/捕获7zip的任何输出 . 所以我的问题是如何通过QProcess和cmd控制台使用命令行应用程序,如ipconfig和7zip,并查看这些应用程序的输出结果?

Example 3: 7zip不起作用

#include <QtCore/QCoreApplication>
#include <QTextStream>
#include <QByteArray>
#include <QProcess>    

int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
   QTextStream qout(stdout);

    QProcess cmd2;
    cmd2.setWorkingDirectory("C:/Program Files/7-Zip");
    cmd2.setReadChannel(QProcess::StandardOutput);
    cmd2.setProcessChannelMode(QProcess::MergedChannels);

    cmd2.start("cmd");
    if (!cmd2.waitForStarted()) {
        return false;
    }

    //My Command
    cmd2.write("7z.exe");
    cmd2.write("\n");

    //Capture output of ipconfig command
    cmd2.waitForReadyRead();
    QByteArray result;

    while (! cmd2.atEnd()) {
        result = cmd2.readLine();
        qout << result;
        result.clear();
    }
    qout << endl;

    qout << "\n\n---end----" << endl;
    return a.exec();
}

Output 贝娄 . 7zip没有显示任何内容 .

Microsoft Windows XP [版本5.1.2600](C)版权所有1985-2001 Microsoft Corp. C:\ Program Files \ 7-Zip> 7z.exe --- end ----

预计产量将符合......

Microsoft Windows XP [版本5.1.2600](C)版权所有1985-2001 Microsoft Corp. C:\ Documents and Settings \ noname> cd C:\ Program Files \ 7-Zip C:\ Program Files \ 7-Zip> 7z .exe 7-Zip 9.15 beta版权所有(c)1999-2010 Igor Pavlov 2010-06-20用法:7z [...] [...] [<@listfiles ...>] a:将文件添加到存档b :基准测试d:从存档中删除文件e:从存档中提取文件(不使用目录名称)l:列出存档的内容t:测试存档的完整性u:更新文件以存档x:使用完整路径的eXtract文件-ai [r [ - | 0]] {@ listfile |!wildcard}:包含档案-ax [r [ - | 0]] {@ listfile |!wildcard}:eXclude archives -bd:禁用百分比指标-i [r [ - | 0] ] {@ listfile |!wildcard}:包含文件名-m {参数}:设置压缩方法-o {目录}:设置输出目录-p {密码}:设置密码-r [ - | 0]:递归子目录-scs { UTF-8 |赢| DOS}:为列表文件设置字符集-sfx []:创建SFX存档-si []:从stdin -slt读取数据:显示l(List)命令的技术信息-so:将数据写入stdout -ssc [ - ]:设置敏感案例模式-ssw:压缩共享文件-t :设置档案类型-u [ - ] [p#] [q#] [r#] [x#] [y#] [z#] [!newArchiveName]:更新选项-v [b | k | m | g]:创建卷-w []:assign工作目录 . 空路径表示临时目录-x [r [ - | 0]]] {@ listfile |!wildcard}:eXclude filenames -y:假设所有查询都为是C:\ Program Files \ 7-Zip>

2 Answers

  • 4

    我看到一个大问题 . 在Windows下,按Enter键发出推荐信 . 写作

    cmd.write("command");
    cmd.write("\n");
    

    只是你不得不写

    cmd.write("command");
    cmd.write("\n\r");
    

    注意尾随\ r \ n . 尝试这个,它应该更好,并且更好,我的意思是7zip . 我不知道你是否会让ipconfig正常工作 .

    祝你好运和最好的问候
    d

    编辑这是一个有效的解决方案:

    #include <QtCore/QCoreApplication>
    #include <QtCore/QProcess>
    #include <QtCore/QString>
    #include <QtCore/QTextStream>
    
    // Not clean, but fast
    QProcess *g_process = NULL;
    
    // Needed as a signal catcher
    class ProcOut : public QObject
    {
      Q_OBJECT
    public:
      ProcOut (QObject *parent = NULL);
      virtual ~ProcOut() {};
    
    public slots:
      void readyRead();
      void finished();
    };
    
    ProcOut::ProcOut (QObject *parent /* = NULL */):
    QObject(parent)
    {}
    
    void
    ProcOut::readyRead()
    {
      if (!g_process)
        return;
    
      QTextStream out(stdout);
      out << g_process->readAllStandardOutput() << endl;
    }
    
    void
    ProcOut::finished()
    {
      QCoreApplication::exit (0);
    }
    
    int main (int argc, char **argv)
    {
      QCoreApplication *app = new QCoreApplication (argc, argv);
    
      ProcOut *procOut = new ProcOut();
      g_process        = new QProcess();
    
      QObject::connect (g_process, SIGNAL(readyReadStandardOutput()),
        procOut, SLOT(readyRead()));
      QObject::connect (g_process, SIGNAL(finished (int, QProcess::ExitStatus)),
        procOut, SLOT(finished()));
    
      g_process->start (QLatin1String ("cmd"));
      g_process->waitForStarted();
    
      g_process->write ("ipconfig\n\r");
    
      // Or cmd won't quit
      g_process->write ("exit\n\r");
    
      int result = app->exec();
    
      // Allright, process finished.
      delete procOut;
      procOut = NULL;
    
      delete g_process;
      g_process = NULL;
    
      delete app;
      app = NULL;
    
      // Lets us see the results
      system ("pause");
    
      return result;
    }
    
    #include "main.moc"
    

    希望有所帮助 . 它每次都在我的机器上工作 .

  • 4

    尽管Dariusz Scharsig已经提供了解决问题的方法,但我想指出我认为可以使用信号槽机制解决的实际问题 .

    Problem 1. while循环中的条件基于 bool QProcess::atEnd () const ,根据QProcess Documentation状态:

    从QIODevice :: atEnd()重新实现 . 如果进程未运行,则返回true,并且没有更多数据可供读取;否则返回false .

    但如果你查看QIODevice::atEnd()的文档,它会说:

    如果当前读写位置位于结尾,则返回true设备(即没有更多数据可供设备读取);否则返回false . 对于某些设备,即使有更多数据要读取,atEnd()也可以返回true . 这种特殊情况仅适用于直接响应您调用read()生成数据的设备(例如,Unix和Mac OS X上的/ dev或/ proc文件,或所有平台上的控制台输入/ stdin) .

    Solution 1. 更改while循环条件以检查进程的状态: while(cmd2.state()!=QProcess::NotRunning){ .

    Problem 2. 您在循环外使用 cmd2.waitForReadyRead(); . 也许有些数据现在已经可以阅读了,当你读完之后,还有一些数据可用:

    • 你读了刚写的命令: ipconfig\n

    • ipconfig需要一些时间来启动并将文本发送到控制台 . 但到那时你已经退出循环,因为即使你的进程仍在运行, atEnd() 也是如此 .

    Solution 2.waitForReadyRead() 放入循环中 .

    Consequence 2. waitForReadyRead() 将告诉您何时有可用数据,哪些可能是多行,因此您也应该将 cmd2.ReadLine() 更改为 cmd2.ReadAll() .

    Problem 3.QProcess::closeWriteChannel()中所述

    关闭写入通道对于读取输入数据直到通道关闭的程序是必要的 .

    Solution 3. 完成输入输入后,以下选项之一应该有效

    • 结束流程: cmd2.write("exit\n");

    • 关闭Writechannel: cmd2.closeWriteChannel();

    工作代码:

    #include <QtCore/QCoreApplication>
    #include <QTextStream>
    #include <QByteArray>
    #include <QString>
    #include <QProcess>    
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        QTextStream qout(stdout);
        QByteArray result;
        QProcess cmd2;
    
        cmd2.setReadChannel(QProcess::StandardOutput);
        cmd2.setProcessChannelMode(QProcess::MergedChannels);
        cmd2.start("cmd");
        if (!cmd2.waitForStarted()){
            qout << "Error: Could not start!" << endl;
            return 0;
        }
        cmd2.write("ipconfig\n");
        cmd2.closeWriteChannel();   //done Writing
    
        while(cmd2.state()!=QProcess::NotRunning){
            cmd2.waitForReadyRead();
            result = cmd2.readAll();
            qout << result;
        }
        qout << endl << "---end----" << endl;
        return a.exec();
    }
    

    我写这个答案只是为了解释我理解你的问题的方式并找到了解决方案,但我想强调的是 Preferable Solution 是使用Signal/Slot Mechanism as presented by Dariusz .

Related