Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2429

CODE-呼叫命令列程式並即時接收輸出

$
0
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
    {
staticint 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;
        }
 
publicstaticint 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;
        }
    }
}

Viewing all articles
Browse latest Browse all 2429

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>