如何获得 System.Diagnostics.Process 的输出?
Posted
技术标签:
【中文标题】如何获得 System.Diagnostics.Process 的输出?【英文标题】:How to get the output of a System.Diagnostics.Process? 【发布时间】:2010-11-26 07:24:19 【问题描述】:我这样运行 ffmpeg:
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegPath, myParams);
p.Start();
p.WaitForExit();
...但问题是带有ffmpeg的控制台弹出并立即消失,所以我无法得到任何反馈。我什至不知道进程是否正确运行。
那我该怎么做:
告诉控制台保持打开状态
在 C# 中检索控制台的内容 显示
【问题讨论】:
【参考方案1】:您需要做的是捕获标准输出流:
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
string q = "";
while ( ! p.HasExited )
q += p.StandardOutput.ReadToEnd();
您可能还需要对StandardError
执行类似的操作。然后你可以用q
做你想做的事。
这有点挑剔,正如我在one of my questions 中发现的那样
正如 Jon Skeet 所指出的,使用这样的字符串连接在性能方面并不明智;你应该改用StringBuilder
:
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
StringBuilder q = new StringBuilder();
while ( ! p.HasExited )
q.Append(p.StandardOutput.ReadToEnd());
string r = q.ToString();
【讨论】:
正确的基本内容,但我不建议这样构建字符串。使用 StringBuilder :) 其实有一个错误:StandardOut 没有被重定向或者进程还没有开始。我试图弄清楚发生了什么 嗯...我不确定。 如果您仍然有问题,请将您的代码发布到pastebin.com,我会看看。 这种方法存在竞争条件:如果进程在进入while循环之前结束,则不会读取输出。【参考方案2】:卢卡斯的回答有一个竞争条件:如果进程很快完成,即使有一些输出,也会留下(或从未进入)while循环,那就是你可能会错过一些数据。为防止这种情况发生,应在进程退出后执行另一个ReadToEnd
。
(请注意,与我的答案的旧版本相比,一旦process.HasExited
标志为真,我就不再需要WaitForExit
,因此归结为:)
using (var process = Process.Start(startInfo))
var standardOutput = new StringBuilder();
// read chunk-wise while process is running.
while (!process.HasExited)
standardOutput.Append(process.StandardOutput.ReadToEnd());
// make sure not to miss out on any remaindings.
standardOutput.Append(process.StandardOutput.ReadToEnd());
// ...
【讨论】:
我相信第一个例子会造成死锁情况。如果进程写入太多输出,它将阻塞等待写入更多输出的机会。对于低于某个阈值的输出,这不会发生。如果它阻塞,它将永远挂起。 [直到被杀] @Cameron - 我已经更新了答案并删除了第一个代码 sn-p。此外,在第二个 sn-p 中,我不再需要WaitToExit
:一旦离开 while 循环,就意味着进程已经退出。但是我不确定你的说法。这意味着即使在您对流程输出不感兴趣的情况下,您也必须始终在代码中添加一个 while-ReadToEnd 结构,无论您想使用Process.Start
启动流程,以确保流程确实如此不要站着等待“空闲空间”。
我在发帖后验证了我的声明。检查一下看看。
ReadToEnd()
是同步的,如果您重定向 stdout 但不从中读取,shell 进程 将 停止,并且该进程会填充其输出缓冲区。在相关的说明中,如果您需要 stdout 和 stderr,则需要对一个或两个使用异步 I/O。见msdn.microsoft.com/en-us/library/…【参考方案3】:
我知道这个问题很老了,但我还是会补充一下。
如果您只想显示命令行进程的输出,并且从控制台窗口生成该进程,则只需重定向标准输入(是的,我知道这听起来不对,但它有效)。
所以:
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = new System.Diagnostics.ProcessStartInfo(ffmpegPath, myParams);
p.UseShellExecute = false;
p.RedirectStandardInput = true;
p.Start();
p.WaitForExit();
会很好。
【讨论】:
您没有添加太多内容,因为已在接受的答案中提到了这一点。 我是喝醉了还是迈克尔·瓦斯奎兹的名字,实际上,他评论周围的大部分 html 都是倒着的? 这是因为在“不是”之后。 utf-8编码有两个U+202E(RIGHT-TO-LEFT OVERRIDE)序列,即0xe2 0x80 0xae 0xe2 0x80 0xae。【参考方案4】:对于与 ffmpeg 直接相关的更具体的答案,将“-report”命令传递给 ffmpeg 将使其将日志转储到当前目录中,其中包含进程显示中所说的内容。
‘-报告’
将完整的命令行和控制台输出转储到一个名为 program-YYYYMMDD-HHMMSS.log 在当前目录下。这个文件可以 对错误报告很有用。它还暗示 -loglevel 详细。
注意:将环境变量 FFREPORT 设置为任何值都有 效果一样。
来自FFMpeg Documentation。
【讨论】:
以上是关于如何获得 System.Diagnostics.Process 的输出?的主要内容,如果未能解决你的问题,请参考以下文章