ProcessStartInfo.RedirectStandardOutput Свойство
Определение
Важно!
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Позволяет получить или задать значение для определения того, записываются ли текстовые выходные данные приложения в поток StandardOutput.
public:
property bool RedirectStandardOutput { bool get(); void set(bool value); };
public bool RedirectStandardOutput { get; set; }
member this.RedirectStandardOutput : bool with get, set
Public Property RedirectStandardOutput As Boolean
Значение свойства
Значение true
, если выходные данные должны записываться в StandardOutput; в противном случае — значение false
. Значение по умолчанию — false
.
Примеры
// Run "cl.exe /cld stdstr.cpp /link /out:sample.exe". UseShellExecute is false because we're specifying
// an executable directly and in this case depending on it being in a PATH folder. By setting
// RedirectStandardOutput to true, the output of cl.exe is directed to the Process.StandardOutput stream
// which is then displayed in this console window directly.
Process^ compiler = gcnew Process;
compiler->StartInfo->FileName = "cl.exe";
compiler->StartInfo->Arguments = "/clr stdstr.cpp /link /out:sample.exe";
compiler->StartInfo->UseShellExecute = false;
compiler->StartInfo->RedirectStandardOutput = true;
compiler->Start();
Console::WriteLine( compiler->StandardOutput->ReadToEnd() );
compiler->WaitForExit();
// Run "csc.exe /r:System.dll /out:sample.exe stdstr.cs". UseShellExecute is false because we're specifying
// an executable directly and in this case depending on it being in a PATH folder. By setting
// RedirectStandardOutput to true, the output of csc.exe is directed to the Process.StandardOutput stream
// which is then displayed in this console window directly.
using (Process compiler = new Process())
{
compiler.StartInfo.FileName = "csc.exe";
compiler.StartInfo.Arguments = "/r:System.dll /out:sample.exe stdstr.cs";
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.Start();
Console.WriteLine(compiler.StandardOutput.ReadToEnd());
compiler.WaitForExit();
}
' Run "vbc.exe /reference:Microsoft.VisualBasic.dll /out:sample.exe stdstr.vb". UseShellExecute is False
' because we're specifying an executable directly and in this case depending on it being in a PATH folder.
' By setting RedirectStandardOutput to True, the output of csc.exe is directed to the Process.StandardOutput
' stream which is then displayed in this console window directly.
Using compiler As New Process()
compiler.StartInfo.FileName = "vbc.exe"
compiler.StartInfo.Arguments = "/reference:Microsoft.VisualBasic.dll /out:sample.exe stdstr.vb"
compiler.StartInfo.UseShellExecute = False
compiler.StartInfo.RedirectStandardOutput = True
compiler.Start()
Console.WriteLine(compiler.StandardOutput.ReadToEnd())
compiler.WaitForExit()
End Using
Комментарии
Когда объект Process записывает текст в свой стандартный поток, этот текст обычно отображается на консоли. Задав для параметра RedirectStandardOutput значение true
для перенаправления StandardOutput потока, можно управлять выходными данными процесса или подавлять их. Например, можно отфильтровать текст, отформатировать его по-другому или записать выходные данные как в консоль, так и в назначенный файл журнала.
Примечание
Если вы хотите задать значение RedirectStandardOutputtrue
, необходимо задать значение UseShellExecutefalse
. В противном случае при чтении StandardOutput из потока создается исключение.
Перенаправленный StandardOutput поток может считываться синхронно или асинхронно. Такие методы, как Read, ReadLineи ReadToEnd , выполняют синхронные операции чтения в выходном потоке процесса. Эти синхронные операции чтения не завершаются до тех пор, пока связанный не Process запишет в свой StandardOutput поток или не закроет поток.
В отличие от этого, BeginOutputReadLine запускает асинхронные операции чтения в потоке StandardOutput . Этот метод включает назначенный обработчик событий (см. OutputDataReceived) для вывода потока и немедленно возвращается вызывающей объекту, который может выполнять другие действия, пока потоковый вывод направляется обработчику событий.
Примечание
Приложение, обрабатывающее асинхронные выходные данные, должно вызвать WaitForExit метод , чтобы убедиться, что выходной буфер был сброшен.
Синхронные операции чтения вводят зависимость между вызывающим объектом, считывающим данные из StandardOutput потока, и дочерним процессом, который записывает данные в этот поток. Эти зависимости могут привести к взаимоблокировки. Когда вызывающий объект считывает из перенаправленного потока дочернего процесса, он зависит от дочернего объекта. Вызывающий объект ожидает операции чтения, пока дочерний элемент не запишет в поток или не закроет поток. Когда дочерний процесс записывает достаточно данных для заполнения перенаправленного потока, он зависит от родительского элемента. Дочерний процесс ожидает следующей операции записи, пока родитель не считывает из полного потока или не закроет поток. Условие взаимоблокировки возникает, когда вызывающий и дочерний процесс ожидают друг друга завершения операции, и ни один из них не может продолжить. Вы можете избежать взаимоблокировок, оценив зависимости между вызывающим и дочерним процессом.
В двух последних примерах в этом разделе используется Start метод для запуска исполняемого файла с именемWrite500Lines.exe. В следующем примере содержится его исходный код.
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.
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:
' 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.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:
// ' 49,800.20%
// Line 500 of 500 written: 49,900.20%
// '
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:
' ' 49,800.20%
' Line 500 of 500 written: 49,900.20%
' '
Аналогичная проблема возникает при чтении всего текста из стандартных выходных данных и стандартных потоков ошибок. В следующем примере выполняется операция чтения в обоих потоках. Это позволяет избежать условия взаимоблокировки, выполняя асинхронные операции чтения в потоке 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:
// ' 49,800.20%
// Line 500 of 500 written: 49,900.20%
// '
//
// 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:
' ' 49,800.20%
' Line 500 of 500 written: 49,900.20%
' '
'
' Error stream: Successfully wrote 500 lines.
Можно использовать асинхронные операции чтения, чтобы избежать этих зависимостей и их возможности взаимоблокировки. Кроме того, можно избежать условия взаимоблокировки, создав два потока и считывая выходные данные каждого потока в отдельном потоке.