1. 程式人生 > >從QProcess說開來(一)

從QProcess說開來(一)

QProcess類的作用是啟動一個外部的程式並與之互動。我們不妨看看:一個普通的控制檯程式,與外界是如何互動的

簡單控制檯程式

一個程式如何從外界獲取資訊並向外輸出資訊呢?

方向

途徑

獲取

命令列引數

int main(int argc, char **argv)

標準輸入

scanf()/getc()/getchar()/…

環境變數

getenv()

輸出

標準輸出

printf() …

標準出錯

fprintf(stderr,…)

返回值

return(x)/exit(X)/_Exit(X)

命令列引數

大多控制檯程式都接受命令列引數,一個例子:

#include <stdio.h>
int main(int argc, char **argv)
{
    for (int i=1; i<argc; ++i)
        printf("%s\n", argv[i]);
    return 0;
}

編譯,呼叫程式時可指定命令列,結果:

$ ./process a b "c d"
a
b
c d

用QProcess呼叫外部程式時,可直接指定命令列引數

QProcess process;
process.start("./process", QStringList()<<"a"<<"b");
process.start("./process a b");

後一種寫法看起來寫起來比較簡潔,但是程式路徑或引數中包括空格時,就不如第一種方便了。

注:在Windows平臺的某些情況(比如QTBUG7620)下,你可能需要使用

  • QProcess::setNativeArguments()


標準輸出


對於控制檯程式來說,這個可能是用的最多的了。比如上一個程式,我們遍歷命令列引數,然後輸到標準輸出。

在控制檯下,我們通常會使用重定向功能,比如:

$./process a b "c d" > out.txt 

在QProcess下,我們使用

QProcess::readAllStandardOutput ()

獲取標準輸出

QProcess::setStandardOutputFile()

設定輸出到的檔案,相當於前面的重定向

QProcess process;
process.start("./process", QStringList()<<"a"<<"b");
process.readAllStandardOutput();

可以使用:

  • QProcess::setStandardOutputProcess()

將標準輸出作為另個程序的標準輸入。形成ls -l | more這樣的管道操作

由於QProcess是QIODevice的派生類,故:

  • read()
  • readLine()

都可以直接用獲取被呼叫程式的標準輸出。

禁止緩衝

注意:如果寫的控制檯程式準備用於這種途徑,且需要實時被讀取標準輸出,那麼一般該程式內需要禁用緩衝

int main()
{
setvbuf(stdout, (char *)NULL, _IONBF, 0);
return 0;
}

因為在控制檯執行時,標準輸出是行緩的。但是使用管道或重定向以後,一般就是全緩衝。在緩衝區寫滿或程式退出前,你可能看不到任何輸出。

標準出錯

相對於標準輸出,這個東西大家似乎用的比較少了。

#include <stdio.h>

int main(int argc, char **argv)
{
    fprintf(stdout, "Hello STDOUT!\n");
    fprintf(stderr, "Hello STDERR!\n");
    return 0;
}

編譯執行(注意區分兩個流,標準出錯的檔案描述符是2):

$ ./process
Hello STDOUT!
Hello STDERR!
$ ./process > out.txt
Hello STDERR!
$ ./process > out.txt 2>err.txt
$

用QProcess讀取標準出錯,和前面標準輸出是類似的:

  • QProcess::readAllStandardError()
  • QProcess::setStandardErrorFile()
QProcess process;
process.start("./process", QStringList()<<"a"<<"b");
process.readAllStandardOutput();

但是,QProcess作為QIODevice的派生類,read()/readAll()只能讀標準輸出,不讀標準出錯,有點說不過去哈。

恩QProcess在這方面足夠靈活,你可以通過

  • QProcess::setReadChannel()

進行選擇

標準輸入

這個也不用多說,使用scanf()/gfets()等函式:

#include <stdio.h>

int main(int argc, char **argv)
{
    char contents[1024];
    fgets(contents, 1024, stdin);
    printf("output: %s", contents);
    return 0;
}

執行:

$ ./process 
1+1=2
output: 1+1=2

如果要輸入的內容在檔案內,也可以使用重定向

$ ./process < intput.txt
output: contents of input.txt

在QProcess中,直接使用QIODevice的write()函式

QProcess process;
process.start("./process")
process.write("intput");

也可以設定檔案作為輸入

  • QProcess::setStandardInputFile()


返回值


似乎很多人分不清返回值和標準輸出的概念。

int main()
{
return 0;
}

也就是程式中 return X/exit(X) 等函式中指定的值了。

在Windows下,通過

C:\> process.exe
C:\> echo %errorlevel%

在Linux下,通過

$ ./process
$ echo $?

獲得返回值。

在QProcess下,則通過:

  • int QProcess::execute()
  • int QProcess::exitCode()

獲得返回值。

環境變數

程式執行時可以通過環境變數傳遞資訊:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    char * path = getenv("MYPATH");
    printf("MYPATH= %s\n", path);
    return 1;
}

執行結果(Linux):

$ export MYPATH="/home/dbzhang800"
$ ./process
MYPATH= /home/dbzhang800

Windows下:

C:\> set MYPATH=E:\dbzhang800
C:\> process.exe
MYPATH= E:\dbzhang800

在Qt下,使用 QProcess::setProcessEnvironment() 設定程序的環境變數

QProcess process;
QProcessEnvironment env;
env.insert("MYPATH", "/home/dbzhang800");
process.setProcessEnvironment(env);
process.start("./process");

本來只是想簡單提一下這部分,然後整理QProcess的其他部分的。沒想到這點東西竟然弄了這麼長,而且還都沒敢展開。不管了,先這樣吧。有時間慢慢寫(二、三、四)。 20111015