• 10295阅读
  • 14回复

[讨论]关于QProcess->setStandardOutputFile()的问题 [复制链接]

上一主题 下一主题
离线asiavikin
 
只看楼主 倒序阅读 楼主  发表于: 2011-09-13
我想在界面里把某个程序A的输出重定向到某个文件里,由于A的运行时间会比较长,所以还要能随时停掉它,我觉得用QProcess来做这个比较合适。事前知道QProcess的start()不能用>符号,所以用了setStandardOutputFile(),但是截取到的数据不是我想要的。想知道为什么setStandardOutputFile()收集到的数据是这个样子。下面是具体的现象:

1.用setStandardOutputFile()收集到的:
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
Not find gain in this line.
.....


2.在linux 命令行下收集到的A的正常输出:
Not find gain in this line.
simulation started:
DEBUG (4): sending->data is
DEBUG (3): Receive buffer data is
DEBUG (3): receiveProbe: Received message data is 0
DEBUG (7): Send buffer data is
DEBUG (7): Send succeeded @ 0:1:55.884334486
DEBUG (7): sending->data is
DEBUG (0): Send buffer data is
DEBUG (0): Send succeeded @ 0:1:55.892482646
DEBUG (0): sending->data is
DEBUG (3): Receive buffer data is
DEBUG (3): receiveProbe: Received message data is 0
.....

也就是说,setStandardOutputFile()收集到的是被测试程序A正常输出的第一行, 而且老是记录这第一行。这是为什么?为什么在linux命令行下运行A从标准输出或是重定向到文件里都不会出这个问题
我的相关界面程序是这样的,很简单:
头文件里:
QProcess *cmd;
QLineEdit *inputEdit;
在cpp文件里:
....
        inputEdit = new QLineEdit;
....
void Process::runClicked()
{
       QString input = inputEdit->text();                             //这里输入A的名称
       cmd->setStandardOutputFile("/tmp/log.txt");           //这里给出A的输出文件,结果就是第一段记录
       cmd->start(input);                                                    //启动A
}

我还试了cmd->execute(“程序A>/tmp/log.txt”);这个办法也不行,不但程序A运行产生的log文件是空的而且程序A本身也终止了。
还请各位方家不吝赐教,谢谢!
离线dbzhang800

只看该作者 1楼 发表于: 2011-09-13
不妨用ls等大家熟悉的东西先测试一下,实在不行也可以将你的测试例程发上来。完整的测试例程最好控制在50行以内。
离线wxj120bw

只看该作者 2楼 发表于: 2011-09-13
回 楼主(asiavikin) 的帖子
A程序最好能打印时间
“cmd->execute(“程序A>/tmp/log.txt”);”你确定这样写吗 命令跟其参数没有空格
不过还是建议按楼上的方法来尝试下
离线asiavikin
只看该作者 3楼 发表于: 2011-09-14
我又用ls、locate 等命令试了,都能正常输出。看来问题是出在我那些程序上,在此谢谢上面两位给我的提示。另外:使用execute()执行时确实要在命令后面添加一个空格,不过怎么在linux命令行下没有那个空格也能正常重定向输出呢?仍旧不理解。
这些被测程序是TinyOS的程序,用nesc写的,大家不一定熟悉。问题可能与nesc的输出机制有关联吧。具体原因恐怕还需要进一步分析,尽管是输出到标准输出,但估计与Qt关系不大。
这里给大家一个TinyOS的例子:这个测试案例有三个程序,两个是nesc的,一个是python的:运行环境是ubuntu,另外还需要下载安装tinyos-2.x才能执行。有兴趣的可以安装tinyos2.x之后试试。
1.nesc程序BlinkC.nc:
#include "Timer.h"

module BlinkC @safe()
{
  uses interface Timer<TMilli> as Timer0;
  uses interface Timer<TMilli> as Timer1;
  uses interface Timer<TMilli> as Timer2;
  uses interface Leds;
  uses interface Boot;
}
implementation
{

  uint8_t counter = 0;
  event void Boot.booted()
  {
    call Timer0.startPeriodic( 250 );
    call Timer1.startPeriodic( 500 );
    call Timer2.startPeriodic( 1000 );

    dbg("Boot","Application booted \n");            
    dbg("Radio","Application booted again.\n");    
    counter ++;
  }

  event void Timer0.fired()
  {
    dbg("BlinkC", "Timer 0 fired @ %s.\n", sim_time_string());          //将输出定向到BlinkC通道,估计就是这里的问题。
    call Leds.led0Toggle();
  }

  event void Timer1.fired()
  {
    dbg("BlinkC", "Timer 1 fired @ %s \n", sim_time_string());
    call Leds.led1Toggle();
  }

  event void Timer2.fired()
  {
    dbg("BlinkC", "Timer 2 fired @ %s.\n", sim_time_string());
    call Leds.led2Toggle();
  }
}

2. nesc程序 BlinkAppC

/**
* Blink is a basic application that toggles the a mote LED periodically.
* It does so by starting a Timer that fires every second. It uses the
* OSKI TimerMilli service to achieve this goal.
*
* @author tinyos-help@millennium.berkeley.edu
**/

configuration BlinkAppC
{
}
implementation
{
  components MainC, BlinkC, LedsC;
  components new TimerMilliC() as Timer0;
  components new TimerMilliC() as Timer1;      
  components new TimerMilliC() as Timer2;


  BlinkC -> MainC.Boot;

  BlinkC.Timer0 -> Timer0;
  BlinkC.Timer1 -> Timer1;
  BlinkC.Timer2 -> Timer2;
  BlinkC.Leds -> LedsC;
}

3.python程序 tinysim.py
from TOSSIM import *
from tinyos.tossim.TossimApp import *

t = Tossim([])
m1 = t.getNode(1)                            //定义节点m1
m2 = t.getNode(2)
m3 = t.getNode(3)

f = open("log.txt","w")
t.addChannel("Boot",sys.stdout)
t.addChannel("Radio",f)
t.addChannel("BlinkC",sys.stdout)     //向标准输出添加BlinkC通道
m1.bootAtTime(345221);                   //节点m1的启动时间
m2.bootAtTime(345222);
m3.bootAtTime(345223);

for i in range (0,100):               //循环运行100次
   t.runNextEvent()



离线asiavikin
只看该作者 4楼 发表于: 2011-09-14
上述nc程序中用到的函数dbg()是sim_log_debug()的别名,其源码如下:
void sim_log_debug(uint16_t id, char* string, const char* format, ...) {
  va_list args;
  int i;
  if (outputs[id].files == NULL) {
    fillInOutput(id, string);
  }
  for (i = 0; i < outputs[id].num; i++) {
    FILE* file = outputs[id].files;
    va_start(args, format);
    fprintf(file, "DEBUG (%i): ", (int)sim_node());
    vfprintf(file, format, args);
    fflush(file);
  }
}看不出这个函数有什么特殊之处啊。

离线asiavikin
只看该作者 5楼 发表于: 2011-09-14
不对啊,刚才又用最简单的helloworld程序试了试,发现它在qprocess下也不能将"hello world"正确输出到用setStandardOutputFile()指定的文件里,难道还是QT的问题?
离线dbzhang800

只看该作者 6楼 发表于: 2011-09-14
引用第5楼asiavikin于2011-09-14 19:48发表的  :
不对啊,刚才又用最简单的helloworld程序试了试,发现它在qprocess下也不能将"hello world"正确输出到用setStandardOutputFile()指定的文件里,难道还是QT的问题?

呵呵,贴你的代码吧,一个简单的helloworld也可能会隐藏一些我们很少考虑的问题
离线asiavikin
只看该作者 7楼 发表于: 2011-09-15
好的,这是我写的两个hello程序,一个c一个c++.
============================
c的hello:

#include <stdio.h>
int main()
{
    int i;
    for ( i = 0; i < 10; i++)
        printf("hello ! %d\n",i);
    return 0;
}
============================
c++的hello:
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
    int i;
    for ( i = 0; i < 10; i++)
         cout<<"Hello,world "<< i <<endl;
    return 0;
}
两个都编译通过并可以在命令行下执行,但在Qprocess下都不输出东西。
离线wxj120bw

只看该作者 8楼 发表于: 2011-09-15
回 7楼(asiavikin) 的帖子
你的c程序输出改成fprintf(stdout, "hello ! %d\n",i);试下(好想是这么写的
离线dbzhang800

只看该作者 9楼 发表于: 2011-09-15
引用第7楼asiavikin于2011-09-15 09:22发表的  :
好的,这是我写的两个hello程序,一个c一个c++.
============================
c的hello:
#include <stdio.h>
.......

可以先使用setvbuf 禁用掉标准输出的缓冲,然后再试。不妨看看其他人是怎么做的 ^_^
  1. // stderr is unbuffered by default, but stdout buffering depends on whether
  2.     // there is a terminal attached. Buffering can make output from stderr and stdout
  3.     // appear out of sync, so force stdout to be unbuffered as well.
  4.     // This is particularly important for things like QtCreator and scripted builds.
  5.     setvbuf(stdout, (char *)NULL, _IONBF, 0);


离线asiavikin
只看该作者 10楼 发表于: 2011-09-15
不行啊,两个办法都试过了,还是没有输出:
第二种办法:
#include <stdio.h>
int main()
{
    int i;
    setvbuf(stdout,NULL,_IONBF,0);
    for ( i = 0; i < 10; i++)
        printf("hello ! %d\n",i);
    return 0;
}
=============================
qt程序:实在不明白是哪里出了问题。

#include <QtGui>
#include "process.h"

Process::Process(QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags)
{
    inputLabel = new QLabel(QObject::tr("Please input command:"));
    inputEdit = new QLineEdit;
    runButton = new QPushButton(tr("Run"));
    killButton = new QPushButton(tr("Kill"));
    quitButton = new QPushButton(tr("Quit"));
    outputLabel = new QLabel(tr("Result:"));
    outputEdit = new QTextEdit;
    outputEdit->setReadOnly(true);

    QHBoxLayout* hlayout = new QHBoxLayout;
    hlayout->addWidget(inputEdit);
    hlayout->addWidget(runButton);
    hlayout->addWidget(killButton);

    QVBoxLayout* layout = new QVBoxLayout;
    layout->addWidget(inputLabel);
    layout->addLayout(hlayout);
    layout->addWidget(outputLabel);
    layout->addWidget(outputEdit);
    layout->addWidget(quitButton);
    setLayout(layout);
    
    cmd = new QProcess;
    cmd->setProcessChannelMode(QProcess::MergedChannels); //fortest
    connect(inputEdit, SIGNAL(returnPressed()), this, SLOT(runClicked()));
    connect(runButton, SIGNAL(clicked(bool)), this, SLOT(runClicked()));
    connect(killButton, SIGNAL(clicked(bool)), this, SLOT(killClicked()));
    connect(quitButton, SIGNAL(clicked(bool)), this, SLOT(close()));
    connect(cmd, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
    resize(500, 300);

    setvbuf(stdout,NULL,_IONBF,0);
}

Process::~Process()
{
}

void Process::runClicked()
{
    QString input = inputEdit->text();
    //input.append(" >log2.txt");
    //cmd->execute(input);
    //cmd->setProcessChannelMode(QProcess::MergedChannels);
    //cmd->setStandardOutputFile("log.txt");
    cmd->start(input);
    output = tr("");
    outputEdit->setText(output);
}

void Process::readOutput()
{
    //output += cmd->readAll();
    output += cmd->readAllStandardOutput();
    outputEdit->setText(output);
}

void Process::killClicked()
{
    cmd->kill();
}
离线dbzhang800

只看该作者 11楼 发表于: 2011-09-15
最关键的地方你没给出来。

  cmd->start(input);

input 是什么东西?用的绝对路径还是相对路径?如果是后者,路径能否保证没有问题(如果你对工作目录的概念非常清晰,可以忽略该问题)?

离线asiavikin
只看该作者 12楼 发表于: 2011-09-16
cmd->start(input);
input我用的是绝对路径,就是怕相对路径不正确。而且,我输入命令了以后还用ps -ef查看了,input所启动的目标进程确实运转着。所以我觉得纳闷,为什么不出东西。
离线wxj120bw

只看该作者 13楼 发表于: 2011-09-16
回 12楼(asiavikin) 的帖子
设置下这个函数setStandardErrorFile()看看有没有输出内容(排除我的猜测
离线asiavikin
只看该作者 14楼 发表于: 2011-09-16
非常感谢两位,我又试了一下,helloworld在相对路径和绝对路径下都能正常输出了,先前我在QT界面下运行时,取相对路径时只是输入了helloworld,正确的应该是输入./helloworld,太大意了。而我的那个工作程序在旧的绝对路径(这个路径是/opt/tinyos-2.1.0/apps/BlinkCom)下仍旧没有输出,不过如果将它复制到QT界面所在的目录下,无论是相对路径还是绝对路径都能正常输出,怪事。
再次感谢两位这些天里的认真指教,让我对QProcess的输出特点有了更多的认识,非常感谢你们!
快速回复
限100 字节
 
上一个 下一个