CODE-呼叫命令列程式並即時接收輸出
| | | 0 | |
之前學過透過RedirectStandardOutput設定,可在.NET呼叫其他命令列程式並接收其顯示內容的技巧。這回則有額外需求,由於某個命令列轉檔工具執行耗時(可能長達數分鐘),故進行期間會持續輸出進度資訊讓使用者安心,但依以前StandardOutput.ReadToEnd()的做法,.NET呼叫端只能在數分鐘後一次取得全部顯示結果,無法即時掌握處理進度,使用者體驗大大扣分。
研究之後,發現貼心的.NET BCL早有因應對策: OutputDataReceived!
做法是先在Process.OutputDataReceived事件上加入處理邏輯,接著呼叫Process.BeginOutputReadLine(),之後外部程式每輸出一行內容,OutputDataReceived事件便被觸發一次,並可由DataReceivedEventArgs.Data取得輸出內容進行自訂處理。
以下的程式範例,一人分飾兩角,展示了OutputDataReceived、ErrorDataReceived、從Output及Error輸出內容、傳回ExitCode等小技巧:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; namespace TestProcOutput { class Program { static int Main(string[] args)
{ //模擬Command Line Utility程式行為 if (args.Length == 1) { switch (args[0]) { case "simu":
//間隔一秒由正常Output輸出0-4 for (int i = 0; i < 5; i++)
{ Console.WriteLine(i);
Thread.Sleep(1000);
}
//正常結束ExitCode = 0 return 0; default: //透過Error TextWriter輸出訊息 Console.Error.WriteLine("Syntax Error!"); //傳回ExtiCode = 1 return 1; }
}
//宣告兩個Callback分別顯示Output及Error接收到的內容 Action<string> outcb = (s) => { Console.WriteLine("OUT:" + s); };
Action<string> errcb = (s) => { Console.WriteLine("ERR:" + s); };
//第一次測試由Output輸出 int exitCode = Execute("TestProcOutput", "simu", outcb, errcb);
Console.WriteLine("ExitCode={0}", exitCode); //第二次則測試由Error輸出 exitCode = Execute("TestProcOutput", "boo", outcb, errcb);
Console.WriteLine("ExitCode={0}", exitCode); Console.Read();
return 0; }
public static int Execute(string exeFile, string argument,
Action<string> outputCallback, Action<string> errorCallback)
{ ProcessStartInfo si = new ProcessStartInfo() { FileName = exeFile,
Arguments = argument,
//必須要設定以下兩個屬性才可將輸出結果導向 UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, //不顯示任何視窗 CreateNoWindow = true };
Process p = new Process() { StartInfo = si,
EnableRaisingEvents = true, };
//開始執行 p.Start();
//透過OutputDataReceived及ErrorDataReceived即時接收輸出內容 p.OutputDataReceived +=
(o, e) =>
{ if (!string.IsNullOrEmpty(e.Data) && outputCallback != null)
{ outputCallback(e.Data);
}
};
p.ErrorDataReceived +=
(o, e) =>
{ if (!string.IsNullOrEmpty(e.Data) && errorCallback != null)
{ errorCallback(e.Data);
}
};
//呼叫Begin*ReadLine()開始接收輸出結果 p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
return p.ExitCode; }
}
}
Comments
Be the first to post a comment