从.NET应用程序捕获控制台输出(C#)

Gri*_*oft 120 .net c# debugging console

如何从.NET应用程序调用控制台应用程序并捕获控制台中生成的所有输出?

(请记住,我不想先将信息保存在文件中,然后重新保存,因为我希望将其作为实时信息接收.)

mdb*_*mdb 155

使用ProcessStartInfo.RedirectStandardOutput属性可以很容易地实现这一点.完整的样本包含在链接的MSDN文档中; 唯一需要注意的是,您可能还需要重定向标准错误流以查看应用程序的所有输出.

Process compiler = new Process();
compiler.StartInfo.FileName = "csc.exe";
compiler.StartInfo.Arguments = "/r:System.dll /out:sample.exe stdstr.cs";
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.Start();    

Console.WriteLine(compiler.StandardOutput.ReadToEnd());

compiler.WaitForExit();
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,如果您将 ReadToEnd() 与能够提示用户输入的控制台应用程序结合使用。例如:覆盖文件:是还是否?etc 然后 ReadToEnd 可能导致内存泄漏,因为进程在等待用户输入时永远不会退出。捕获输出的更安全方法是使用 process.OutputDataReceived 事件处理程序,并让进程通知您的应用程序要接收的输出。 (3认同)
  • 如果你不想在最后添加额外的新行,只需使用`Console.Write`. (2认同)

Shi*_*hah 29

这比@mdb接受的答案有点改进.具体来说,我们还捕获过程的错误输出.此外,我们通过捕获这些事件,因为输出ReadToEnd的(),如果你想捕捉不起作用两个错误和常规输出.我花了很长时间才能完成这项工作,因为它实际上还需要在Start()之后调用BeginxxxReadLine().

using System.Diagnostics;

Process process = new Process();

void LaunchProcess()
{
    process.EnableRaisingEvents = true;
    process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived);
    process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived);
    process.Exited += new System.EventHandler(process_Exited);

    process.StartInfo.FileName = "some.exe";
    process.StartInfo.Arguments = "param1 param2";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardOutput = true;

    process.Start();
    process.BeginErrorReadLine();
    process.BeginOutputReadLine();          

    //below line is optional if we want a blocking call
    //process.WaitForExit();
}

void process_Exited(object sender, EventArgs e)
{
    Console.WriteLine(string.Format("process exited with code {0}\n", process.ExitCode.ToString()));
}

void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine(e.Data + "\n");
}

void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine(e.Data + "\n");
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你。太棒了。 (3认同)
  • 谢谢你,多年来一直在寻找这个! (2认同)
  • 这是很容易理解、漂亮的代码。我唯一的挑剔是你不必要地添加换行符。“writeline”为您添加了一个,因此最终效果是您捕获的输出每隔一行插入一个空行。 (2认同)

Fra*_*nov 13

在创建控制台进程时,使用ProcessInfo.RedirectStandardOutput重定向输出.

然后,您可以使用Process.StandardOutput读取程序输出.

第二个链接有一个示例代码如何操作.


Sla*_*aGu 7

ConsoleAppLauncher是一个专门用于回答该问题的开源库.它捕获控制台中生成的所有输出,并提供启动和关闭控制台应用程序的简单界面.

每次控制台将新行写入标准/错误输出时,都会触发ConsoleOutput事件.这些行排队并保证遵循输出顺序.

也可以作为NuGet包.

获取完整控制台输出的示例调用:

// Run simplest shell command and return its output.
public static string GetWindowsVersion()
{
    return ConsoleApp.Run("cmd", "/c ver").Output.Trim();
}
Run Code Online (Sandbox Code Playgroud)

实时反馈示例:

// Run ping.exe asynchronously and return roundtrip times back to the caller in a callback
public static void PingUrl(string url, Action<string> replyHandler)
{
    var regex = new Regex("(time=|Average = )(?<time>.*?ms)", RegexOptions.Compiled);
    var app = new ConsoleApp("ping", url);
    app.ConsoleOutput += (o, args) =>
    {
        var match = regex.Match(args.Line);
        if (match.Success)
        {
            var roundtripTime = match.Groups["time"].Value;
            replyHandler(roundtripTime);
        }
    };
    app.Run();
}
Run Code Online (Sandbox Code Playgroud)