如何获取Process.Start打开进程的输出结果?

咨询区

  • stighy

我想用 C# 通过控制台开启一个外部程序,理论上我就可以让程序和这个外部程序实现交互,但现在我遇到了两个问题。

  1. 如何获取控制台上的输出呢?我想将结果写到我的 textbox 上。

  2. 如何获取数值型的值让我可以展示进度条。.

回答区

  • Ferruccio

可以实例化一个 Process 并赋值 StartInfo 属性,比如下面这样:

var proc = new Process 
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "program.exe",
        Arguments = "command line arguments to your executable",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

然后就可以把进程启动起来并从控制台中读取结果。

proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    // do something with line
}

你可以使用 int.Parse() 或 int.TryParse() 方法将 string 转成 numeric 值,建议用 try 方式,这样可以处理非 numeric 时的逻辑。

  • Tyrrrz

System.Diagnostics.Process 属于比较底层的东西,我在项目中并不待见它,换言之我更愿意使用 CliWrap 这样的开源工具包,它提供了很多实用的功能,比如: 管道操作,缓存,流式处理,参考如下的例子:

  1. 启动控制台。
using CliWrap;
var result = await Cli.Wrap("path/to/exe")
    .WithArguments("--foo bar")
    .WithWorkingDirectory("work/dir/path")
    .ExecuteAsync();
    
// Result contains:
// -- result.ExitCode        (int)
// -- result.StartTime       (DateTimeOffset)
// -- result.ExitTime        (DateTimeOffset)
// -- result.RunTime         (TimeSpan)
  1. 启动控制台接收事件流
using CliWrap;
using CliWrap.EventStream;
var cmd = Cli.Wrap("foo").WithArguments("bar");
await foreach (var cmdEvent in cmd.ListenAsync())
{
    switch (cmdEvent)
    {
        case StartedCommandEvent started:
            _output.WriteLine($"Process started; ID: {started.ProcessId}");
            break;
        case StandardOutputCommandEvent stdOut:
            _output.WriteLine($"Out> {stdOut.Text}");
            break;
        case StandardErrorCommandEvent stdErr:
            _output.WriteLine($"Err> {stdErr.Text}");
            break;
        case ExitedCommandEvent exited:
            _output.WriteLine($"Process exited; Code: {exited.ExitCode}");
            break;
    }
}

点评区

个人建议使用第三方的开源包,作者能写出一套肯定也是踩了不少坑,都是一些经验总结哈!