【问题标题】:ProcessInfo and RedirectStandardOutputProcessInfo 和 RedirectStandardOutput
【发布时间】:2020-03-11 21:58:38
【问题描述】:

我有一个应用程序在命令窗口中调用另一个进程,并且该进程更新了输出到控制台窗口的统计信息。我认为这是一个相当简单的操作,但我似乎无法让它工作。我错过了什么吗?

string assemblyLocation = Assembly.GetExecutingAssembly().Location;

Process process = new Process
{
    ProcessStart =
    {
        RedirectStandardOutput = true,
        UseShellExecute = false,
        WindowStyle = ProcessWindowStyle.Hidden,
        Arguments = arg,
        FileName = assemblyLocation.Substring(0, assemblyLocation.LastIndexOf("\\")) + "\\ffmpeg.exe",
        CreateNoWindow = true
    }
};

process.Start();

Console.WriteLine(process.StandardOutput.ReadToEnd());

process.WaitForExit();

理想情况下,我想要的是当我遇到的那个过程中的输出发生变化或数据进入阅读器时,我从中获得了事件。

任何帮助都会很棒,我觉得这是一个新手问题,但似乎缺少一些东西。

【问题讨论】:

    标签: c# .net redirectstandardoutput startprocessinfo


    【解决方案1】:

    我以前经历过。有时,您调用输出到控制台的过程的方式与这种输出重定向不兼容。在这种情况下,我很幸运能够修改外部流程来解决这个问题。

    您可以尝试在另一个输出到控制台的进程上运行您的代码,看看它是否正常工作。它现在对我来说是正确的。

    编辑:

    我去拉了一个我用来做这个的代码块。这是在将进程输出重定向到窗口的 WPF 应用程序中。注意事件绑定。由于这是 WPF,我必须调用我的调用来写出数据。由于您不担心阻塞,您应该能够简单地将其替换为:

    Console.WriteLine(e.Data);
    

    希望对您有所帮助!

        private static void LaunchProcess()
        {
            Process build = new Process();
            build.StartInfo.WorkingDirectory =  @"dir";
            build.StartInfo.Arguments = "";
            build.StartInfo.FileName = "my.exe";
    
            build.StartInfo.UseShellExecute = false;
            build.StartInfo.RedirectStandardOutput = true;
            build.StartInfo.RedirectStandardError = true;
            build.StartInfo.CreateNoWindow = true;
            build.ErrorDataReceived += build_ErrorDataReceived;
            build.OutputDataReceived += build_ErrorDataReceived;
            build.EnableRaisingEvents = true;
            build.Start();
            build.BeginOutputReadLine();
            build.BeginErrorReadLine();
            build.WaitForExit();
        }
    
        // write out info to the display window
        static void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            string strMessage = e.Data;
            if (richTextBox != null && !String.Empty(strMessage))
            {
                App.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate()
                {
                    Paragraph para = new Paragraph(new Run(strMessage));
                    para.Margin = new Thickness(0);
                    para.Background = brushErrorBrush;
                    box.Document.Blocks.Add(para);
                });
           }
        } 
    

    【讨论】:

    • 你的意思是另一个线程或另一个进程?我可以从 cmd 行运行该过程,并且输出看起来不错。
    • 我的意思是与您尝试的过程不同。在我遇到的实例中,当我重定向标准输出时,进程不会在以这种方式启动时清除它的输出缓冲区,因此流最终会全部通过。这可能是也可能不是您的问题。请参阅我的代码示例,了解我如何在自己的应用中处理此问题。
    • 我可以让它与大多数控制台应用程序一起工作,但不是 PowerShell。有什么想法吗?
    • @David Lively,您可以尝试未记录的 PowerShell 参数 -InputFormat none。
    • @PeterStephens 这是新的——我一定会试一试的。
    【解决方案2】:

    我不确定您到底遇到了什么问题,但如果您希望在输出生成后立即对其进行操作,请尝试连接到进程的 OutputDataReceived 事件。您可以指定处理程序以从流程异步接收输出。我已经成功地使用了这种方法。

    Process p = new Process();
    ProcessStartInfo info = p.info;
    info.UseShellExecute = false;
    info.RedirectStandardOutput = true;
    info.RedirectStandardError = true;
    
    p.OutputDataReceived += p_OutputDataReceived;
    p.ErrorDataReceived += p_ErrorDataReceived;
    
    p.Start();
    
    p.BeginOutputReadLine();
    p.BeginErrorReadLine();
    p.WaitForExit();
    

    ..

    void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
      Console.WriteLine("Received from standard out: " + e.Data);
    }
    
    void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
      Console.WriteLine("Received from standard error: " + e.Data);
    }
    

    查看OutputDataReceived事件关闭进程了解更多信息。

    【讨论】:

    • 你需要Start()WaitForExit()之前的一个进程
    • 对不起!我的疏忽。被Process p = Process.Start(info);弄糊涂了
    • 优秀的解决方案!这也解决了我遇到的一个问题,即过多的控制台输出导致生成的进程挂在 Console.WriteLine 上。谢谢!
    • @MichaelPetrotta 非常感谢先生! ..这像魅力一样解决了我的问题:D
    • 通常您应该在开始进程之前附加事件处理程序。否则您可能会错过活动。
    【解决方案3】:

    使用 lambda 表达式等:

    var info = new ProcessStartInfo(path)
    {
        RedirectStandardError = true,
        RedirectStandardOutput = true,
        UseShellExecute = false,
        Verb = "runas",
    };
    
    var process = new Process
    {
        EnableRaisingEvents = true,
        StartInfo = info
    };
    
    Action<object, DataReceivedEventArgs> actionWrite = (sender, e) =>
    {
        Console.WriteLine(e.Data);
    };
    
    process.ErrorDataReceived += (sender, e) => actionWrite(sender, e);
    process.OutputDataReceived += (sender, e) => actionWrite(sender, e);
    
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit();
    

    【讨论】:

    • 只有一个说明:动词“runas”只有在 UseShellExecute = true, Verb = “runas”时才有效。如果 UseShellExecute = true 你不能重定向输出。查看更多kiquenet.wordpress.com/2014/08/22/…
    • 这是对捕获输出中的一些细微差别的一个很好的细分。感谢您将这些放在一起。
    【解决方案4】:

    有趣的是,您不能同时从标准输出和标准错误中读取:

    如果您同时重定向标准输出和标准错误,然后尝试读取两者,对于 使用以下 C# 代码的示例。

    [C#]

    字符串输出 = p.StandardOutput.ReadToEnd();

    字符串错误 = p.StandardError.ReadToEnd();

    p.WaitForExit();

    在这种情况下,如果子进程将任何文本写入标准错误,它将阻塞 进程,因为父进程在完成之前无法从标准错误中读取 从标准输出读取。但是,父进程不会从标准中读取 输出直到过程结束。针对这种情况的推荐解决方案是创建两个 线程,以便您的应用程序可以在单独的线程上读取每个流的输出。

    http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.71).aspx

    【讨论】:

    • 不能没有办法读取两个流,只是同时在两个流上只使用同步方法是不安全的。我只是想澄清@jeremy-mcgee 说“不正确”不会使答案中的引用信息不正确。
    【解决方案5】:

    在 VS2010 中工作的流动代码

    void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (String.IsNullOrEmpty(e.Data) == false)
            {
                new Thread(() =>
                {
                    this.Dispatcher.Invoke(new Action(() =>
                    {
                        // Add you code here
                    }));
                }).Start();
            }
        }
    

    【讨论】:

    • 什么是调度程序? 这个是什么?什么是 OnOutputDataReceived 事件?什么是 DataReceivedEventArgs 类型?您的源代码的完整上下文是什么?
    【解决方案6】:

    检查您期望的输出没有被发送到 StandardError 输出而不是 StandardOutput 输出

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-06
      • 1970-01-01
      • 2014-12-25
      相关资源
      最近更新 更多