为什么即使在进程终止后仍未完成异步读取?
我编写了一个Process,它从作为参数给出的文件中读取数据。 我已同步异步读取StandardOutput和StandardError。
public static string ProcessScript(string command, string arguments) { Process proc = new Process(); proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.RedirectStandardError = true; proc.StartInfo.FileName = command; proc.StartInfo.Arguments = arguments; proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; proc.Start(); string error = null; string output = null; proc.OutputDataReceived += (sender, outputLine) => { if (outputLine.Data != null) { output += outputLine.Data; } }; proc.BeginOutputReadLine(); error = proc.StandardError.ReadToEnd(); proc.WaitForExit(); proc.Close(); //I have not got entire Output return output; }
完成该过程后,我将获得输出。 但并非完全如此。 我只得到部分数据。 即使在进程完成任务之后,异步读取也没有结束,所以只有我得到部分数据。 我需要完整的字符串。
编辑:
我正在使用.Net 3.5。 我不能使用ReadToEndAsync
方法
有任何想法吗?
您可以直接从实际输出流中直接读取(假设您使用的是.NET 4.5,这要归功于其添加的异步function),而不是处理事件并处理由此产生的问题。
public static string ProcessScript(string command, string arguments) { Process proc = new Process(); proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; proc.StartInfo.RedirectStandardError = true; proc.StartInfo.FileName = command; proc.StartInfo.Arguments = arguments; proc.Start(); var output = proc.StandardOutput.ReadToEndAsync(); var error = proc.StandardError.ReadToEndAsync(); proc.WaitForExit(); proc.Close(); var errorContent = error.Result; return output.Result; }
这里由ReadToEndAsync
表示的Task
在其结果表示的全部数据之前不会实际完成。 这意味着您要等到拥有所有数据而不是等待进程完成 ,因为这两个数据可能不完全相同。
根据这篇文章 ,事件处理程序可能在WaitForExit
完成后触发。 我试图找出如何使用Reflector,但我看不到它。 无论如何,我经历过这样的事情。
这篇文章还讲述了如何处理这个问题的秘诀:显然,当没有更多的输入将会出现时,使用null
数据调用事件处理程序。 所以你需要等待这种情况。
我认为Servy解决这个问题的方法更胜一筹。 我只是在这里记录这种行为。
重复https://stackoverflow.com/a/25772586/2065863
在WaitForExit(timeout)
返回true
后调用WaitForExit()
(无参数):
if (process.WaitForExit(timeout) && process.WaitForExit()) { // do stuff: async read will be completed here }
有关详细信息,请阅读此处的评论: https : //msdn.microsoft.com/en-us/library/ty0d8k56(v=vs.110).aspx