C#使用Process的StandardOutput遇到阻塞的问题及解决方案

原文地址: https://www.jeremyjone.com/518/, 转载请注明。
项目中使用ffprobe插件读取视频信息,不用想,肯定要是用Process创建进程,然后使用StandardOuput接收输出。然而在测试的时候,发现程序一直卡在ffprobe的进程。
我试过的方案
1、看到有人说需要把p.StandardOutput.ReadToEnd()放到p.WaitForExit()后面,还信誓旦旦的说,如果放在之前,会接收不到任何信息,因为ReadToEnd()是同步函数。

  • 然后我上官方文档查看了一下,确认ReadToEnd()同时支持同步和异步,所以根本不对。而且官方文档也是将p.StandardOutput.ReadToEnd()放到p.WaitForExit()前面使用的。
2、使用StandardError接收信息。有人说试了好长时间,StandardOutput不会接收到任何信息,反而使用StandardError能顺利接收到信息。
  • 我尝试了一下,纯属胡扯。我同样接收不到任何消息。这样做的人是这样解释的:StandardOutput属于同步,StandardError属于异步,所以使用StandardError可以接收信息。根据第一种失败的方案得到的结论,这个方案同样失败。
我的最终解决方案
其实最好的答案就在官方文档中,它的介绍里有一句These synchronous read operations do not complete until the associated Process writes to its StandardOutput stream, or closes the stream.
于是在写完之后,我尝试手动关闭它,然后惊喜的发现,它正常了。。。
string result = String.Empty; using (Process p = new Process()) { p.StartInfo.UseShellExecute = false; // 如果使用StandardOutput接收,这项必须为false(来自官方文档) p.StartInfo.CreateNoWindow = true; // 是否创建窗口,true为不创建 p.StartInfo.RedirectStandardOutput = true; // 使用StandardOutput接收,一定要重定向标准输出,否则会报InvalidOperationException异常 p.StartInfo.FileName = Path.Combine(ffmpegPath, "ffprobe.exe"); // 设置启动文件路径 p.StartInfo.Arguments = $" -v error -print_format json -show_streams -show_format \"{Path.GetFullPath(Path.Combine(localPath, videoName))}\""; // 设置参数 p.Start(); // 启动进程 StreamReader reader = p.StandardOutput; // 创建输出流 result = reader.ReadToEnd(); // 接收信息 // 这里注意了,当读取完成,手动关闭输出流,确保流关闭后,进程才会退出。 reader.Close(); // 关闭输出流 p.WaitForExit(); p.Close(); p.Dispose(); }

【C#使用Process的StandardOutput遇到阻塞的问题及解决方案】嗯,大致就是这样的。

    推荐阅读