Process.StandardOutput 属性

定义

获取用于读取应用程序文本输出的流。

C#
public System.IO.StreamReader StandardOutput { get; }
C#
[System.ComponentModel.Browsable(false)]
public System.IO.StreamReader StandardOutput { get; }

属性值

StreamReader,可用于读取应用程序的标准输出流。

属性

例外

尚未对 StandardOutput 流进行重定向定义;请确保 RedirectStandardOutput 设置为 trueUseShellExecute 设置为 false

已打开 StandardOutput 流,以使用 BeginOutputReadLine() 进行异步读取操作。

示例

以下示例运行 ipconfig.exe 命令,并将其标准输出重定向到示例的控制台窗口。

C#
using System;
using System.IO;
using System.Diagnostics;

class StandardOutputExample
{
    public static void Main()
    {
        using (Process process = new Process())
        {
            process.StartInfo.FileName = "ipconfig.exe";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.Start();

            // Synchronously read the standard output of the spawned process.
            StreamReader reader = process.StandardOutput;
            string output = reader.ReadToEnd();

            // Write the redirected output to this application's window.
            Console.WriteLine(output);

            process.WaitForExit();
        }

        Console.WriteLine("\n\nPress any key to exit.");
        Console.ReadLine();
    }
}

注解

当将 Process 文本写入其标准流时,该文本通常显示在主机上。 通过重定向 StandardOutput 流,可以操作或禁止显示进程的输出。 例如,可以筛选文本、设置不同的格式,或将输出写入控制台和指定的日志文件。

备注

若要使用 StandardOutput,必须将 设置为 ProcessStartInfo.UseShellExecutefalse,并且必须设置为 ProcessStartInfo.RedirectStandardOutputtrue。 否则,从流中 StandardOutput 读取会引发异常。

重定向的 StandardOutput 流可以同步或异步读取。 、 和 ReadToEndReadReadLine方法对进程的输出流执行同步读取操作。 这些同步读取操作在关联 Process 写入其 StandardOutput 流或关闭流之前不会完成。

相比之下,对 BeginOutputReadLineStandardOutput 流启动异步读取操作。 此方法为流输出启用指定的事件处理程序,并立即返回到调用方,后者可以在流输出定向到事件处理程序时执行其他工作。

同步读取操作在从流读取的调用方与写入该 StandardOutput 流的子进程之间引入了依赖关系。 这些依赖项可能会导致死锁情况。 当调用方从子进程的重定向流中读取时,它依赖于子进程。 调用方等待读取操作,直到子写入流或关闭流。 当子进程写入足够的数据来填充其重定向流时,它依赖于父进程。 子进程等待下一个写入操作,直到父进程从完整流读取或关闭流。 当调用方和子进程相互等待完成操作并且两者都无法继续时,会导致死锁情况。 可以通过评估调用方和子进程之间的依赖关系来避免死锁。

本节中的最后两个示例使用 Start 方法启动名为 Write500Lines.exe的可执行文件。 以下示例包含其源代码。

C#
using System;
using System.IO;

public class Example3
{
   public static void Main()
   {
      for (int ctr = 0; ctr < 500; ctr++)
         Console.WriteLine($"Line {ctr + 1} of 500 written: {ctr + 1/500.0:P2}");

      Console.Error.WriteLine("\nSuccessfully wrote 500 lines.\n");
   }
}
// The example displays the following output:
//      The last 50 characters in the output stream are:
//      ' 49,800.20%
//      Line 500 of 500 written: 49,900.20%
//'
//
//      Error stream: Successfully wrote 500 lines.

以下示例演示如何从重定向的流中读取并等待子进程退出。 该示例通过在 之前p.WaitForExit调用 p.StandardOutput.ReadToEnd 来避免死锁条件。 如果父进程先调用 p.WaitForExitp.StandardOutput.ReadToEnd 子进程写入足够的文本来填充重定向的流,则可能会导致死锁情况。 父进程将无限期等待子进程退出。 子进程将无限期等待父进程从完整 StandardOutput 流中读取数据。

C#
using System;
using System.Diagnostics;

public class Example2
{
   public static void Main()
   {
      var p = new Process();  
      p.StartInfo.UseShellExecute = false;  
      p.StartInfo.RedirectStandardOutput = true;  
      p.StartInfo.FileName = "Write500Lines.exe";  
      p.Start();  

      // To avoid deadlocks, always read the output stream first and then wait.  
      string output = p.StandardOutput.ReadToEnd();  
      p.WaitForExit();

      Console.WriteLine($"The last 50 characters in the output stream are:\n'{output.Substring(output.Length - 50)}'");
   }
}
// The example displays the following output:
//      Successfully wrote 500 lines.
//
//      The last 50 characters in the output stream are:
//      ' 49,800.20%
//      Line 500 of 500 written: 49,900.20%
//      '

从标准输出流和标准错误流读取所有文本时,也会出现类似的问题。 以下示例对两个流执行读取操作。 它通过在流上 StandardError 执行异步读取操作来避免死锁情况。 如果父进程调用 p.StandardOutput.ReadToEndp.StandardError.ReadToEnd 跟 ,并且子进程写入足够的文本来填充其错误流,则会导致死锁条件。 父进程将无限期等待子进程关闭其 StandardOutput 流。 子进程将无限期等待父进程从完整 StandardError 流中读取数据。

C#
using System;
using System.Diagnostics;

public class Example
{
   public static void Main()
   {
      var p = new Process();  
      p.StartInfo.UseShellExecute = false;  
      p.StartInfo.RedirectStandardOutput = true;  
      string eOut = null;
      p.StartInfo.RedirectStandardError = true;
      p.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => 
                                 { eOut += e.Data; });
      p.StartInfo.FileName = "Write500Lines.exe";  
      p.Start();  

      // To avoid deadlocks, use an asynchronous read operation on at least one of the streams.  
      p.BeginErrorReadLine();
      string output = p.StandardOutput.ReadToEnd();  
      p.WaitForExit();

      Console.WriteLine($"The last 50 characters in the output stream are:\n'{output.Substring(output.Length - 50)}'");
      Console.WriteLine($"\nError stream: {eOut}");
   }
}
// The example displays the following output:
//      The last 50 characters in the output stream are:
//      ' 49,800.20%
//      Line 500 of 500 written: 49,900.20%
//      '
//
//      Error stream: Successfully wrote 500 lines.

可以使用异步读取操作来避免这些依赖项及其死锁的可能性。 或者,可以通过在单独的线程上创建两个线程并读取每个流的输出来避免死锁情况。

备注

不能在重定向流上混合执行异步读取操作和同步读取操作。 在异步或同步模式下打开 的重定向流 Process 后,该流上的所有进一步读取操作都必须处于同一模式。 例如,不要在流上执行 BeginOutputReadLineReadLineStandardOutput 调用,反之亦然。 但是,可以在不同的模式下读取两个不同的流。 例如,可以调用 BeginOutputReadLine 流,然后调用 ReadLineStandardError

适用于

产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

另请参阅