如何获得 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 的输出?的主要内容,如果未能解决你的问题,请参考以下文章

求教,如何获得comboBox中当前选择的值

如何获得物体度数?

如何在一行上获得 3d 瓷砖并在悬停时获得缩放效果?

PHP如何获得POST传来的值?

CSDN如何获取C币

SQl中如何获得时间的时,分,秒部分?