Process.StandardOutput Свойство

Определение

Получает поток, используемый для чтения текстовых выходных данных приложения.

public:
 property System::IO::StreamReader ^ StandardOutput { System::IO::StreamReader ^ get(); };
public System.IO.StreamReader StandardOutput { get; }
[System.ComponentModel.Browsable(false)]
public System.IO.StreamReader StandardOutput { get; }
member this.StandardOutput : System.IO.StreamReader
[<System.ComponentModel.Browsable(false)>]
member this.StandardOutput : System.IO.StreamReader
Public ReadOnly Property StandardOutput As StreamReader

Значение свойства

Значение StreamReader , которое можно использовать для чтения стандартного выходного потока приложения.

Атрибуты

Исключения

Поток StandardOutput не определен для перенаправления; убедитесь RedirectStandardOutput , что задано true значение и UseShellExecute имеет falseзначение .

–или–

Поток StandardOutput был открыт для асинхронных операций чтения с BeginOutputReadLine().

Примеры

В следующем примере выполняется команда ipconfig.exe и перенаправляет стандартные выходные данные в окно консоли примера.

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

open System.Diagnostics

use proc = new Process()
proc.StartInfo.FileName <- "ipconfig.exe"
proc.StartInfo.UseShellExecute <- false
proc.StartInfo.RedirectStandardOutput <- true
proc.Start() |> ignore

// Synchronously read the standard output of the spawned process.
let reader = proc.StandardOutput
let output = reader.ReadToEnd()

// Write the redirected output to this application's window.
printfn $"{output}"

proc.WaitForExit()

printfn "\n\nPress any key to exit."
stdin.ReadLine() |> ignore
Imports System.IO
Imports System.Diagnostics

Module Module1
    Sub Main()
        Using process As 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. 
            Dim reader As StreamReader = process.StandardOutput
            Dim output As String = reader.ReadToEnd()
            Console.WriteLine(output)

            process.WaitForExit()
        End Using

        Console.WriteLine(Environment.NewLine + Environment.NewLine + "Press any key to exit.")
        Console.ReadLine()
    End Sub
End Module

Комментарии

Когда текст записывается в стандартный Process поток, этот текст обычно отображается в консоли. Перенаправляя StandardOutput поток, вы можете управлять выходными данными процесса или подавлять их. Например, можно отфильтровать текст, отформатировать его по-разному или записать выходные данные в консоль и в указанный файл журнала.

Note

Чтобы использовать StandardOutput, необходимо задать ProcessStartInfo.UseShellExecutefalseзначение , и необходимо задать значение ProcessStartInfo.RedirectStandardOutputtrue. В противном случае чтение из StandardOutput потока вызывает исключение.

Перенаправленный StandardOutput поток можно считывать синхронно или асинхронно. Такие методы, как Read, ReadLineи ReadToEnd выполняют синхронные операции чтения в выходном потоке процесса. Эти синхронные операции чтения не завершаются до тех пор, пока связанные Process операции записи в поток StandardOutput не закрываются или закрывают поток.

В отличие от этого, BeginOutputReadLine запускает асинхронные операции чтения в потоке StandardOutput . Этот метод включает назначенный обработчик событий для выходных данных потока и немедленно возвращает вызывающий объект, который может выполнять другую работу во время передачи потока в обработчик событий.

Синхронные операции чтения представляют зависимость между вызывающим чтением из StandardOutput потока и дочерним процессом записи в этот поток. Эти зависимости могут привести к взаимоблокировке. Когда вызывающий объект считывает перенаправленный поток дочернего процесса, он зависит от дочернего. Вызывающий объект ожидает операции чтения, пока дочерний пользователь не записывает в поток или закрывает поток. Когда дочерний процесс записывает достаточно данных для заполнения перенаправленного потока, он зависит от родительского элемента. Дочерний процесс ожидает следующей операции записи, пока родитель не считывает из полного потока или закрывает поток. Условие взаимоблокировки приводит к тому, что вызывающий и дочерний процесс ожидают завершения операции, и ни один из них не может продолжаться. Можно избежать взаимоблокировок, оценивая зависимости между вызывающим и дочерним процессом.

В последних двух примерах этого раздела используется Start метод для запуска исполняемого файла с именем Write500Lines.exe. В следующем примере содержится исходный код.

using System;

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:
//      Line 1 of 500 written: 0,20%
//      Line 2 of 500 written: 0,40%
//      Line 3 of 500 written: 0,60%
//      ...
//      Line 498 of 500 written: 99,60%
//      Line 499 of 500 written: 99,80%
//      Line 500 of 500 written: 100,00%
//
//      Successfully wrote 500 lines.
module Write500Lines

for i in 1. .. 500. do
    printfn $"Line {i} of 500 written: {i/500.:P2}";

eprintfn "Successfully wrote 500 lines.";
// The example displays the following output:
//      Line 1 of 500 written: 0,20%
//      Line 2 of 500 written: 0,40%
//      Line 3 of 500 written: 0,60%
//      ...
//      Line 498 of 500 written: 99,60%
//      Line 499 of 500 written: 99,80%
//      Line 500 of 500 written: 100,00%
//      Successfully wrote 500 lines.
Imports System.IO

Public Module Example
   Public Sub Main()
      For ctr As Integer = 0 To 499
         Console.WriteLine($"Line {ctr + 1} of 500 written: {(ctr + 1) / 500.0:P2}")
      Next

      Console.Error.WriteLine($"{vbCrLf}Successfully wrote 500 lines.{vbCrLf}")
   End Sub
End Module
' The example displays the following output:
'      Line 1 of 500 written 0,20%
'      Line 2 of 500 written: 0,40%
'      Line 3 of 500 written: 0,60%
'      ...
'      Line 498 of 500 written: 99,60%
'      Line 499 of 500 written: 99,80%
'      Line 500 of 500 written: 100,00%
'
'      Successfully wrote 500 lines.

В следующем примере показано, как считывать из перенаправленного потока и ожидать завершения дочернего процесса. В этом примере не вызывается условие взаимоблокировки перед p.StandardOutput.ReadToEndвызовомp.WaitForExit. Условие взаимоблокировки может привести к тому, что родительский процесс вызывается p.WaitForExit до p.StandardOutput.ReadToEnd и дочерний процесс записывает достаточно текста для заполнения перенаправленного потока. Родительский процесс будет ждать неограниченное время, пока дочерний процесс завершится. Дочерний процесс будет ждать неограниченное время, пока родитель будет считывать из полного StandardOutput потока.

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:
//      'ritten: 99,80%
//      Line 500 of 500 written: 100,00%
//      '
module STDOutputSync

open System.Diagnostics

let p = new Process()
p.StartInfo.UseShellExecute <- false
p.StartInfo.RedirectStandardOutput <- true
p.StartInfo.FileName <- "Write500Lines.exe"
p.Start() |> ignore

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

printfn $"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:
//      'ritten: 99,80%
//      Line 500 of 500 written: 100,00%
//      '
Imports System.Diagnostics'

Public Module Example
   Public Sub Main()
      Dim p As 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.  
      Dim output As String = p.StandardOutput.ReadToEnd()  
      p.WaitForExit()

      Console.WriteLine($"The last 50 characters in the output stream are:\n'{output.Substring(output.Length - 50)}'")
   End Sub
End Module
' The example displays the following output:
'      Successfully wrote 500 lines.
'
'      The last 50 characters in the output stream are:
'      'ritten: 99,80%
'      Line 500 of 500 written: 100,00%
'      '

При чтении всего текста из стандартных выходных и стандартных потоков ошибок возникает аналогичная проблема. В следующем примере выполняется операция чтения в обоих потоках. Это позволяет избежать взаимоблокировки путем выполнения асинхронных операций чтения в потоке StandardError . Условие взаимоблокировки приводит к вызову p.StandardOutput.ReadToEnd родительского процесса, за которым следует, p.StandardError.ReadToEnd и дочерний процесс записывает достаточно текста для заполнения потока ошибок. Родительский процесс будет ждать неограниченное время, пока дочерний процесс завершит свой StandardOutput поток. Дочерний процесс будет ждать неограниченное время, пока родитель будет считывать из полного StandardError потока.

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:
//      'ritten: 99,80%
//      Line 500 of 500 written: 100,00%
//      '
//
//      Error stream: Successfully wrote 500 lines.
module STDOutputAsync

open System.Diagnostics

let p = new Process()
p.StartInfo.UseShellExecute <- false
p.StartInfo.RedirectStandardOutput <- true
let mutable eOut = ""
p.StartInfo.RedirectStandardError <- true
p.ErrorDataReceived.AddHandler(DataReceivedEventHandler(fun sender e -> eOut <- eOut + e.Data))

p.StartInfo.FileName <- "Write500Lines.exe"
p.Start() |> ignore

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

printfn $"The last 50 characters in the output stream are:\n'{output.Substring(output.Length - 50)}'"
printfn $"\nError stream: {eOut}"
// The example displays the following output:
//      The last 50 characters in the output stream are:
//      'ritten: 99,80%
//      Line 500 of 500 written: 100,00%
//      '
//
//      Error stream: Successfully wrote 500 lines.
Imports System.Diagnostics

Public Module Example
   Public Sub Main()
      Dim p As New Process()  
      p.StartInfo.UseShellExecute = False  
      p.StartInfo.RedirectStandardOutput = True  
      Dim eOut As String = Nothing
      p.StartInfo.RedirectStandardError = True
      AddHandler p.ErrorDataReceived, Sub(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()
      Dim output As String = p.StandardOutput.ReadToEnd()  
      p.WaitForExit()

      Console.WriteLine($"The last 50 characters in the output stream are:{vbCrLf}'{output.Substring(output.Length - 50)}'")
      Console.WriteLine($"{vbCrLf}Error stream: {eOut}")
   End Sub
End Module
' The example displays the following output:
'      The last 50 characters in the output stream are:
'      'ritten: 99,80%
'      Line 500 of 500 written: 100,00%
'      '
'
'      Error stream: Successfully wrote 500 lines.

Вы можете использовать асинхронные операции чтения, чтобы избежать этих зависимостей и их возможности взаимоблокировки. Кроме того, можно избежать взаимоблокировки, создав два потока и считывая выходные данные каждого потока в отдельном потоке.

Note

Вы не можете смешивать асинхронные и синхронные операции чтения в перенаправленном потоке. После открытия перенаправленного потока в Process асинхронном или синхронном режиме все дальнейшие операции чтения в этом потоке должны находиться в одном и том же режиме. Например, не следует следовать BeginOutputReadLine вызову ReadLine в потоке StandardOutput или наоборот. Однако можно читать два разных потока в разных режимах. Например, можно вызвать BeginOutputReadLine и вызвать ReadLineStandardError поток.

Применяется к

См. также раздел