C# ProcessInfo 和 RedirectStandardOutput

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1145969/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:19:22  来源:igfitidea点击:

ProcessInfo and RedirectStandardOutput

c#.netredirectstandardoutputstartprocessinfo

提问by Brandon Grossutti

I have an app which calls another process in a command window and that process has updating stats that output to the console window. I thought this was a fairly simple operation but I can't seem to get it to work. Am I missing something?

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

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();

Ideally what I would like is as the output changes within that process I hit or data comes into the reader that I get events off it.

理想情况下,我想要的是当我点击的过程中的输出发生变化或数据进入阅读器时,我会从中获取事件。

Any help would be great, I feel like this is a newbie question but seem to be missing something.

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

采纳答案by patjbs

I've experienced this before. Sometimes, the way in which the process you're calling outputs to the console is not compatible with this sort of output redirection. I've been fortunate enough in this case to be able to modify the external process to get around this.

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

You might try running your code on another process that outputs to the console, and see if it works properly. It reads about right to me right now.

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

EDIT:

编辑:

I went and pulled a code block I've used to do this. This is in a WPF app which redirects the process output to the window. Notice the event binding. Since this is WPF I have to invoke my call to write the data out. Since you aren't worried about blocking, ou should be able to simply replace that with:

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

Console.WriteLine(e.Data);

Hopefully it helps!

希望它有帮助!

    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);
            });
       }
    } 

回答by Michael Petrotta

I'm not sure exactly what problem you're running into, but if you're looking to act on output as soon as it's generated, try hooking into the process's OutputDataReceivedevent. You can specify handlers to receive output asynchronously from the process. I've used this approach successfully.

我不确定您遇到了什么问题,但是如果您希望在输出生成后立即对其采取行动,请尝试挂钩流程的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);
}

See the OutputDataReceivedevent off Process for more information.

有关详细信息,请参阅Process的OutputDataReceived事件。

回答by abatishchev

Using lambda expressions, etc:

使用 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();

回答by Matthew Lock

Interestingly you can't read from standard output and standard error at the same time:

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

if you redirect both standard output and standard error and then try to read both, for example using the following C# code.

[C#]

string output = p.StandardOutput.ReadToEnd();

string error = p.StandardError.ReadToEnd();

p.WaitForExit();

In this case, if the child process writes any text to standard error it will block the process, because the parent process cannot read from standard error until it has finished reading from standard output. However, the parent process will not read from standard output until the process ends. A recommended solution to this situation is to create two threads so that your application can read the output of each stream on a separate thread.

如果您重定向标准输出和标准错误,然后尝试读取两者,例如使用以下 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

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

回答by stackuser83

Check that the output you are expecting is not being sent to the StandardError output instead of the StandardOutput output

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

回答by Rock

flowing code worked in VS2010

在 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();
        }
    }