ProcessStartInfo.RedirectStandardOutput 属性
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
获取或设置指示是否将应用程序的文本输出写入 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
属性值
如果输出应写入 StandardOutput,则为 true
;否则为 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 文本写入其标准流时,该文本通常显示在主机上。 通过将 设置为 RedirectStandardOutputtrue
以重定向 StandardOutput 流,可以操作或禁止进程输出。 例如,可以筛选文本、设置不同的格式,或将输出写入控制台和指定的日志文件。
注意
如果要设置为 UseShellExecutefalse
,则必须将 设置为 RedirectStandardOutputtrue
。 否则,从流中 StandardOutput 读取会引发异常。
重定向的 StandardOutput 流可以同步或异步读取。 、 和 ReadToEnd 等ReadReadLine方法对进程的输出流执行同步读取操作。 这些同步读取操作在关联 Process 写入其 StandardOutput 流或关闭流之前不会完成。
相比之下,对 BeginOutputReadLineStandardOutput 流启动异步读取操作。 此方法启用指定的事件处理程序, (查看 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.WaitForExit
调用 p.StandardOutput.ReadToEnd
来避免死锁条件。 如果父进程先调用 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.
可以使用异步读取操作来避免这些依赖项及其死锁的可能性。 或者,可以通过在单独的线程上创建两个线程并读取每个流的输出来避免死锁情况。