我正在使用.NET和C#来启动进程并异步读取它的输出。我的问题是在我的程序读取输出之前似乎有一段延迟。如果我在命令行上运行可执行文件,它会在开始运行时立即输出。但是当我使用我的代码运行它时,在Process退出之前不会调用ReadOutput事件处理程序。我想使用它来提供进程输出的实时视图,所以我不想等待(几分钟)直到进程退出。
以下是一些相关代码:
MyProcess = new Process();
MyProcess.StartInfo.FileName = command;
MyProcess.StartInfo.Arguments = args;
MyProcess.StartInfo.UseShellExecute = false;
MyProcess.StartInfo.RedirectStandardOutput = true;
MyProcess.StartInfo.RedirectStandardError = true;
MyProcess.StartInfo.RedirectStandardInput = true;
MyProcess.OutputDataReceived += new DataReceivedEventHandler(ReadOutput);
MyProcess.ErrorDataReceived += new DataReceivedEventHandler(ReadOutput);
if (!MyProcess.Start())
{
throw new Exception("Process could not be started");
}
try
{
MyProcess.BeginOutputReadLine();
MyProcess.BeginErrorReadLine();
}
catch (Exception ex)
{
throw new Exception("Unable to begin asynchronous reading from process";
}
这是我的事件处理程序:
private void ReadOutput(object sendingProcess, DataReceivedEventArgs outLine)
{
OutputBuilder.AppendLine(outLine.Data);
Console.WriteLine(outLine.Data);
Console.Out.Flush();
}
答案 0 :(得分:3)
根据我使用lambda语法的注释,这就是我这样做的方式(C#3)。
/// <summary>
/// Collects standard output text from the launched program.
/// </summary>
private static readonly StringBuilder outputText = new StringBuilder();
/// <summary>
/// Collects standard error text from the launched program.
/// </summary>
private static readonly StringBuilder errorText = new StringBuilder();
/// <summary>
/// The program's entry point.
/// </summary>
/// <param name="args">The command-line arguments.</param>
/// <returns>The exit code.</returns>
private static int Main(string[] args)
{
using (var process = Process.Start(new ProcessStartInfo(
"program.exe",
args)
{
CreateNoWindow = true,
ErrorDialog = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false
}))
{
process.OutputDataReceived += (sendingProcess, outLine) =>
outputText.AppendLine(outLine.Data);
process.ErrorDataReceived += (sendingProcess, errorLine) =>
errorText.AppendLine(errorLine.Data);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
Console.WriteLine(errorText.ToString());
Console.WriteLine(outputText.ToString());
return process.ExitCode;
}
答案 1 :(得分:1)
您的方法中的问题可能是该进程仅在退出时完成一行的输出。没有办法控制异步事件处理程序何时触发。
在控制台应用程序中,最好的办法是定期检查新输出并同步读取和显示:
while (!p.HasExited)
{
if (!p.StandardOutput.EndOfStream)
{
errorBuilder.Append(p.StandardError.ReadToEnd());
outputBuilder.Append(p.StandardOutput.ReadToEnd());
Console.Write(p.StandardOutput);
}
else
{
Thread.Sleep(200);
}
}
在UI项目中,您分别对WinForms和WPF使用Timer
或DispatcherTimer
来调用循环内容并更新UI。
请注意,我不会刷新Console.Out
,因为Console.Write()
和Console.WriteLine()
会自动导致此问题。
答案 2 :(得分:0)
尝试添加MyProcess.WaitForExit
方法调用:
MyProcess.BeginOutputReadLine();
MyProcess.BeginErrorReadLine();
// will wait for the associated process to exit
MyProcess.WaitForExit();