30

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

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

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

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

4

6 回答 6

51

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

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

编辑:

我去拉了一个我用来做这个的代码块。这是在将进程输出重定向到窗口的 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);
            });
       }
    } 
于 2009-07-17T22:37:57.393 回答
25

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

于 2009-07-17T22:50:14.967 回答
13

使用 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();
于 2010-08-28T22:46:18.303 回答
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

于 2011-11-24T05:21:19.383 回答
1

流动代码在 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();
        }
    }
于 2013-11-26T15:43:12.820 回答
0

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

于 2013-10-31T18:12:20.040 回答