【问题标题】:How to get the output of a System.Diagnostics.Process?如何获得 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# 中检索控制台的内容 显示

【问题讨论】:

    标签: c# asp.net windows system.diagnostics


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-15
      • 2019-03-09
      • 1970-01-01
      • 1970-01-01
      • 2011-05-16
      • 1970-01-01
      • 2013-10-16
      相关资源
      最近更新 更多