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

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

(请记住,我不想先将信息保存在文件中,然后再重新列出,因为我希望以实时方式接收它。)

149497 次浏览

使用 重定向标准输出属性可以很容易地实现这一点。完整的示例包含在链接的 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();

在创建控制台进程时,使用 重定向标准输出重定向输出。

然后可以使用 过程,标准输出读取程序输出。

第二个链接有一个示例代码如何做到这一点。

来自 Python-Python Programc Derne i,e-kitap,örnek :

Process p = new Process();   // Create new object
p.StartInfo.UseShellExecute = false;  // Do not use shell
p.StartInfo.RedirectStandardOutput = true;   // Redirect output
p.StartInfo.FileName = "c:\\python26\\python.exe";   // Path of our Python compiler
p.StartInfo.Arguments = "c:\\python26\\Hello_C_Python.py";   // Path of the .py to be executed

我已经向 氧气平台(开源项目)添加了许多助手方法,它们允许您通过控制台输出和输入(参见 http://code.google.com/p/o2platform/source/browse/trunk/O2_Scripts/APIs/Windows/CmdExe/CmdExeAPI.cs)轻松地编写与另一个进程的交互脚本

同样有用的 API 可能允许查看当前进程的控制台输出(在现有控件或弹出窗口中)。有关更多细节,请参阅这篇博客文章: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/(这篇博客还包含如何使用新进程的控制台输出的细节)

Console AppLauncher 是一个专门用来回答这个问题的开源库。它捕捉控制台中生成的所有输出,并提供简单的界面来启动和关闭控制台应用。

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

也可作为 NuGet 软件包

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

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

实时反馈样本:

// 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();
}

增加了 process.StartInfo.**CreateNoWindow** = true;timeout

private static void CaptureConsoleAppOutput(string exeName, string arguments, int timeoutMilliseconds, out int exitCode, out string output)
{
using (Process process = new Process())
{
process.StartInfo.FileName = exeName;
process.StartInfo.Arguments = arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();


output = process.StandardOutput.ReadToEnd();


bool exited = process.WaitForExit(timeoutMilliseconds);
if (exited)
{
exitCode = process.ExitCode;
}
else
{
exitCode = -1;
}
}
}

这是从 @ mdb接受的答案位改进。具体来说,我们还捕获流程的错误输出。此外,我们通过事件捕获这些输出,因为如果您想捕获 都有错误和常规输出,ReadToEnd()不起作用。我花了一段时间才做到这一点,因为它实际上也需要 BeginxxxReadLine()调用后 Start()

异步方式:

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");
}

我做了一个反应版本,它接受 stdOut 和 StdErr 的回调。
onStdOutonStdErr是异步调用的,
一旦数据到达(在进程退出之前)。

public static Int32 RunProcess(String path,
String args,
Action<String> onStdOut = null,
Action<String> onStdErr = null)
{
var readStdOut = onStdOut != null;
var readStdErr = onStdErr != null;


var process = new Process
{
StartInfo =
{
FileName = path,
Arguments = args,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = readStdOut,
RedirectStandardError = readStdErr,
}
};


process.Start();


if (readStdOut) Task.Run(() => ReadStream(process.StandardOutput, onStdOut));
if (readStdErr) Task.Run(() => ReadStream(process.StandardError, onStdErr));


process.WaitForExit();


return process.ExitCode;
}


private static void ReadStream(TextReader textReader, Action<String> callback)
{
while (true)
{
var line = textReader.ReadLine();
if (line == null)
break;


callback(line);
}
}


示例用法

下面将使用 args运行 executable并打印

  • 白色标准输出
  • 红色的

到控制台。

RunProcess(
executable,
args,
s => { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(s); },
s => { Console.ForegroundColor = ConsoleColor.Red;   Console.WriteLine(s); }
);