QProcess问题,输出过程

时间:2011-05-04 23:16:17

标签: qt qt4

我试图找出QProcess的用法。我没有运气地看着Qt doc http://doc.qt.io/qt-4.8/qprocess.html

问题示例。

示例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();
}

上述代码的输出

  

您好

F:\Dev_Qt\expControllingExtConsoleApps-build-desktop>

---End, bye----

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

示例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();

}

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

  

Microsoft Windows XP [版本   5.1.2600](C)版权所有1985-2001 Microsoft Corp.

     

C:\ Program Files \ 7-Zip&gt; IPCONFIG

     

--- ----结束

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

  

Microsoft Windows XP [版本   5.1.2600](C)版权所有1985-2001 Microsoft Corp.

     

C:\ Documents and   设置\ NONAME&GT; IPCONFIG

     

Windows IP配置

     

以太网适配器本地区域   连接:

    Connection-specific DNS Suffix  . :
    IP Address. . . . . . . . . . . . : 192.172.148.135
    Subnet Mask . . . . . . . . . . . : 255.255.255.0
    Default Gateway . . . . . . . . . : 192.172.148.177
     

C:\ Documents and Settings \ noname&gt;

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

示例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();
}
下面是

输出。没有显示7zip的任何内容。

  

Microsoft Windows XP [版本   5.1.2600](C)版权所有1985-2001 Microsoft Corp.

     

C:\ Program Files \ 7-Zip&gt; 7z.exe

     

--- ----结束

预计产出将符合......

  

Microsoft Windows XP [版本   5.1.2600](C)版权所有1985-2001 Microsoft Corp.

     

C:\ Documents and Settings \ noname&gt; cd   C:\ Program Files \ 7-Zip

     

C:\ Program Files \ 7-Zip&gt; 7z.exe

     

7-Zip 9.15 beta版权所有(c)   1999-2010 Igor Pavlov 2010-06-20

     

用法:7z [...]    [...]          并[d @listfiles ...&GT;]

     

a:将文件添加到存档中   b:基准测试d:从中删除文件   存档e:从中提取文件   存档(不使用目录   名称)l:列出档案的内容
  t:测试档案的完整性你:   更新文件以存档x:eXtract   完整路径的文件
  -ai [r [ - | 0]] {@ listfile |!wildcard}:包含档案
  -ax [r [ - | 0]] {@ listfile |!wildcard}:eXclude archives -bd:Disable   百分比指标
  -i [r [ - | 0]] {@ listfile |!wildcard}:包含文件名-m {Parameters}:   设定压缩方法
  -o {Directory}:set输出目录-p {Password}:set Password -r [ - | 0]:Recurse子目录-scs {UTF-8 |   赢| DOS}:为列表文件设置charset   -sfx [{name}]:创建SFX存档-si [{name}]:从stdin -slt读取数据:显示l(List)命令的技术信息-so:将数据写入   stdout -ssc [ - ]:设置敏感案例   mode -ssw:压缩共享文件
  -t {Type}:设置档案类型-u [ - ] [p#] [q#] [r#] [x#] [y#] [z#] [!newArchiveName]:   更新选项-v {Size} [b | k | m | g]:   创建卷-w [{path}]:assign   工作目录。空路径意味着   临时目录
  -x [r [ - | 0]]] {@ listfile |!wildcard}:eXclude文件名-y:假设是   所有查询

     

C:\ Program Files \ 7-Zip&gt;

2 个答案:

答案 0 :(得分:4)

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

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

你还不够写

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

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

祝你好运和最好的问候 d

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


#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"

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

答案 1 :(得分:4)

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

问题1。您的while循环中的条件基于bool QProcess::atEnd () const,符合QProcess Documentation州:

  

从QIODevice :: atEnd()重新实现。

     

如果进程是,则返回true   没有运行,没有更多的数据可供阅读;除此以外   返回false。

但如果您查看QIODevice::atEnd()的文档,则说明:

  

如果当前读写位置在末尾,则返回true   该设备(即没有更多的数据可供阅读   设备);否则返回false。

     

对于某些设备,atEnd()可以返回   即使有更多数据需要阅读也是如此。仅限这种特殊情况   适用于直接响应您生成数据的设备   调用read()(例如,Unix和Mac OS X上的/ dev或/ proc文件,或者   所有平台上的控制台输入/ stdin )。

解决方案1。更改while循环条件以检查流程的状态:while(cmd2.state()!=QProcess::NotRunning){

问题2。您在循环之外使用cmd2.waitForReadyRead();。也许有些数据现在可供阅读,当你读完之后,还有更多数据可用:

  • 您阅读了刚写的命令:ipconfig\n
  • ipconfig需要一些时间来启动并将文本发送到控制台。但到那时你已经退出了循环,因为即使你的进程仍然在运行,atEnd()也是如此。

解决方案2. waitForReadyRead()放入循环中。

结果2。 waitForReadyRead()会告诉您何时有可用的数据,哪些可能不止一行,因此您也应该将cmd2.ReadLine()更改为{{ 1}}。

问题3。如[{3}}

中所述
  

关闭读写输入的程序需要关闭写通道   数据直到频道关闭。

解决方案3。完成输入

后,以下选项之一应该有效
  • 结束流程:cmd2.ReadAll()
  • 关闭Writechannel:cmd2.write("exit\n");

工作代码:

cmd2.closeWriteChannel();

我写这个答案只是为了解释我理解你的问题并找到解决方案的方式,但我想强调优先解决方案是使用QProcess::closeWriteChannel()