在 .NET 中异步读取 cmd 输出 - 挂起处理输入请求
Asynchronously read cmd output in .NET - Hanging on process input request
在使用一些参数启动批处理文件后,我正在异步读取批处理文件的输出。如果批处理文件正在等待输入 - 输入请求文本未被重定向 - 除非进程终止(这显然来不及响应)。
如果在标准cmd中执行window,提示为:
OpenEdge Release 10.2B07 as of Fri Sep 7 02:16:54 EDT 2012
testdb already exists.
Do you want to over write it? [y/n]:
使用重定向时输出会挂起,不会触发outputdatarecieved事件,所以我无法处理输入请求并做出相应响应。控制台没有读取最后一行(输入请求):
OpenEdge Release 10.2B07 as of Fri Sep 7 02:16:54 EDT 2012
testdb already exists.
代码:
Private Sub someMethod()
Dim process As New Process()
process.StartInfo = New ProcessStartInfo("C:\OEV10\bin\_dbutil")
process.StartInfo.WorkingDirectory = "C:\Temp\"
process.StartInfo.Arguments = "prorest testdb C:\Temp\testdb.bck -verbose"
process.EnableRaisingEvents = True
With process.StartInfo
.UseShellExecute = False
.RedirectStandardError = True
.RedirectStandardOutput = True
.RedirectStandardInput = True
.CreateNoWindow = False
.StandardOutputEncoding = System.Text.Encoding.GetEncoding(Globalization.CultureInfo.CurrentUICulture.TextInfo.OEMCodePage)
.StandardErrorEncoding = System.Text.Encoding.GetEncoding(Globalization.CultureInfo.CurrentUICulture.TextInfo.OEMCodePage)
End With
AddHandler process.Exited, AddressOf ProcessExited
AddHandler process.OutputDataReceived, AddressOf Async_Data_Received2
AddHandler process.ErrorDataReceived, AddressOf Async_Data_Received2
process.Start()
process.BeginOutputReadLine()
process.BeginErrorReadLine()
End Sub
Private Sub Async_Data_Received2(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
Console.WriteLine(e.Data)
End Sub
您可以编写自己的文本流reader例程,它将读取并报告不完整的行。这是一个简单的 C# 实现:
public static async Task ReadTextReaderAsync(TextReader reader, IProgress<string> progress) {
char[] buffer = new char[1024];
for(;;) {
int count = await reader.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
if(count==0) {
break;
}
progress.Report(new string(buffer, 0, count));
}
}
此实现仅从 TextReader
读取字符串并通过 IProgress<string>
实例报告它们。它不会按换行符拆分字符串,而是将它们保留在字符串中。和一个测试程序:
public static void Main() {
ProcessStartInfo psi = new ProcessStartInfo("Test.cmd") {
UseShellExecute=false,
RedirectStandardOutput=true,
RedirectStandardError=true
};
Process p = Process.Start(psi);
// Progress<T> implementation of IProgress<T> capture current SynchronizationContext,
// so if you create Progress<T> instance in UI thread, then passed delegate
// will be invoked in UI thread and you will be able to interact with UI elements.
Progress<string> writeToConsole = new Progress<string>(Console.Write);
Task stdout = ReadTextReaderAsync(p.StandardOutput, writeToConsole);
Task stderr = ReadTextReaderAsync(p.StandardError, writeToConsole);
// You possibly want asynchronous wait here, but for simplicity I will use synchronous wait.
p.WaitForExit();
stdout.Wait();
stderr.Wait();
}
在使用一些参数启动批处理文件后,我正在异步读取批处理文件的输出。如果批处理文件正在等待输入 - 输入请求文本未被重定向 - 除非进程终止(这显然来不及响应)。
如果在标准cmd中执行window,提示为:
OpenEdge Release 10.2B07 as of Fri Sep 7 02:16:54 EDT 2012
testdb already exists.
Do you want to over write it? [y/n]:
使用重定向时输出会挂起,不会触发outputdatarecieved事件,所以我无法处理输入请求并做出相应响应。控制台没有读取最后一行(输入请求):
OpenEdge Release 10.2B07 as of Fri Sep 7 02:16:54 EDT 2012
testdb already exists.
代码:
Private Sub someMethod()
Dim process As New Process()
process.StartInfo = New ProcessStartInfo("C:\OEV10\bin\_dbutil")
process.StartInfo.WorkingDirectory = "C:\Temp\"
process.StartInfo.Arguments = "prorest testdb C:\Temp\testdb.bck -verbose"
process.EnableRaisingEvents = True
With process.StartInfo
.UseShellExecute = False
.RedirectStandardError = True
.RedirectStandardOutput = True
.RedirectStandardInput = True
.CreateNoWindow = False
.StandardOutputEncoding = System.Text.Encoding.GetEncoding(Globalization.CultureInfo.CurrentUICulture.TextInfo.OEMCodePage)
.StandardErrorEncoding = System.Text.Encoding.GetEncoding(Globalization.CultureInfo.CurrentUICulture.TextInfo.OEMCodePage)
End With
AddHandler process.Exited, AddressOf ProcessExited
AddHandler process.OutputDataReceived, AddressOf Async_Data_Received2
AddHandler process.ErrorDataReceived, AddressOf Async_Data_Received2
process.Start()
process.BeginOutputReadLine()
process.BeginErrorReadLine()
End Sub
Private Sub Async_Data_Received2(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
Console.WriteLine(e.Data)
End Sub
您可以编写自己的文本流reader例程,它将读取并报告不完整的行。这是一个简单的 C# 实现:
public static async Task ReadTextReaderAsync(TextReader reader, IProgress<string> progress) {
char[] buffer = new char[1024];
for(;;) {
int count = await reader.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
if(count==0) {
break;
}
progress.Report(new string(buffer, 0, count));
}
}
此实现仅从 TextReader
读取字符串并通过 IProgress<string>
实例报告它们。它不会按换行符拆分字符串,而是将它们保留在字符串中。和一个测试程序:
public static void Main() {
ProcessStartInfo psi = new ProcessStartInfo("Test.cmd") {
UseShellExecute=false,
RedirectStandardOutput=true,
RedirectStandardError=true
};
Process p = Process.Start(psi);
// Progress<T> implementation of IProgress<T> capture current SynchronizationContext,
// so if you create Progress<T> instance in UI thread, then passed delegate
// will be invoked in UI thread and you will be able to interact with UI elements.
Progress<string> writeToConsole = new Progress<string>(Console.Write);
Task stdout = ReadTextReaderAsync(p.StandardOutput, writeToConsole);
Task stderr = ReadTextReaderAsync(p.StandardError, writeToConsole);
// You possibly want asynchronous wait here, but for simplicity I will use synchronous wait.
p.WaitForExit();
stdout.Wait();
stderr.Wait();
}