經常看到論壇中有人問到當用Process組件啟動新的進程後如何獲取它的輸出的問題采取將子進程的輸出定向到一個臨時文件中當然也可以解決問題但是這樣每次父進程從臨時文件中獲取信息後還要刪除該臨時文件畢竟比較麻煩其實Process提供了幾個屬性可以獲取輸出框架sdk的幫助文檔裡面就有這方面的例子但是對於如何同時獲取錯誤輸出和標准輸出方面沒有給出具體代碼本文將給出實例並對管道的特性作一些說明
一獲取子進程標准輸出和錯誤輸出的的方法
我們寫一個小程序pcs用它來產生標准輸出和錯誤輸出
//pcs代碼如下
using System;
class class
{
public static void Main()
{
int i = ;
string s = StringFormat(out:{}i);
SystemConsoleOutWriteLine(s);
string s = StringFormat(err:{}**************************************************i);
SystemConsoleErrorWriteLine(s);
}
}
編譯成pexe
獲取子進程的標准輸出和錯誤輸出的源程序
//pcs
Process p = new Process(pexe);
pStartInfoUseShellExecute = false; //指定不使用系統的外殼程序而是直接啟動被調用程序本身
pStartInfoRedirectStandardOutput = true; //只有將此屬性設為true才能通過管道獲取子進程輸出
pStartInfoRedirectStandardError = true;
pStart(); //啟動子進程
string output = pStandardOutputReadToEnd(); //讀取標准輸出
string error = pStandardErrorReadToEnd(); //讀取錯誤輸出
pWaitForExit(); //等待子進程執行完畢
上例中父進程啟動子進程後就等待著從管道中取走標准輸出取走全部標准輸出後取走錯誤輸出我們運行起來沒有任何錯誤但是一旦我門增加pexe中的標准輸出和錯誤輸出的字節數
for(i=;i<;i++)
SystemConsoleOutWriteLine(s);
for(i=;i<;i++)
SystemConsoleErrorWriteLine(s);
編譯後再運行就會發現父進程和子進程出現了死鎖只有強行關閉才能終止進程
二管道
Process 組件通過管道與子進程進行通訊如果同時重定向標准輸出和標准錯誤然後試圖讀取它們當管道被填滿時候就會出現問題上例中父進程只有讀完了所有的標准輸出才能讀錯誤輸出而子進程的標准輸出每當把管道填滿時候父進程都會取走子進程接著向管道輸出後續的標准輸出這都運行的很好可是當子進程執行到輸出錯誤輸出的時候由於子進程還沒有運行結束它的標准輸出流就不會處於結束狀態(雖然在我們的例子中它的次循環的標准輸出已經執行完畢)這就導致父進程中的ReadToEnd()方法不會執行完畢所以父進程中的pStandardErrorReadToEnd()無法執行從而管道中的錯誤輸出無法被讀取子進程的後續錯誤輸出無法寫入管道最終子進程和父進程彼此無限等待出現了阻塞情況
子進程通過檢查管道中最後一個字節是否被取走來決定是否輸出後續內容也就是說如果管道緩沖區中最後一個字節之前的所有內容都被取走子進程仍然會處於等待中如果前面所有字節都沒有取走但最後一個字節內容被取走子進程會繼續向管道裡輸出後續內容當然這樣只能輸出一字節到管道中最後位置
我們如果把pcs中的string output = pStandardOutputReadToEnd()改為
for(int i=;i<*;i++)
ConsoleWrite((char) pStandardOutputRead());
就不會出現死鎖情況因為當獲取標准輸出的循環執行完後會接著執行獲取錯誤輸出的語句而不需等待標准輸出流的結束但是這種方法毫無實際意義因為實際中我們並不可能像本例中知道標准輸出會有多少字節
三用多線程分別獲取標准輸出和錯誤輸出
對於這種情況框架文檔中建議這樣解決創建兩個線程以便應用程序可以在單獨的線程上讀取每個流的輸出下面給出例子:
//pcs:
class class
{
public static void Main()
{
ProcessStartInfo pi = new ProcessStartInfo();
piFileName = @c:\pexe;
piUseShellExecute = false;
piRedirectStandardOutput = true;
piRedirectStandardError = true;
SystemDiagnosticsProcess p = new Process();
pStartInfo = pi;
pStart();
tout t = new tout(p);
terr t = new terr(p);
Thread thread = new Thread(new ThreadStart(tRead));
Thread thread = new Thread(new ThreadStart(tRead));
threadStart();
threadStart();
pWaitForExit();
ConsoleWriteLine(pexe結束);
}
}
class tout
{
Process p;
public tout(Process p)
{
thisp = p;
}
public void Read()
{
int a = ;
while((a = pStandardOutputRead()) > )
{
ConsoleWrite( ((char) a)ToString() );
}
ThreadCurrentThreadAbort();
return;
}
}
class terr
{
Process p;
public terr(Process p)
{
thisp = p;
}
public void Read()
{
int a = ;
while((a = pStandardErrorRead()) > )
{
ConsoleWrite(((char) a)ToString());
}
ThreadCurrentThreadAbort();
return;
}
}
From:http://tw.wingwit.com/Article/program/net/201311/11610.html