【问题标题】:Asynchronously read cmd output in .NET - Hanging on process input request在 .NET 中异步读取 cmd 输出 - 挂在进程输入请求上
【发布时间】:2016-02-24 07:36:02
【问题描述】:

在使用一些参数启动批处理文件后,我正在异步读取批处理文件的输出。如果批处理文件正在等待输入 - 输入请求文本没有被重定向 - 除非进程终止(这显然来不及响应)。

如果在标准cmd窗口执行,提示为:

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

【问题讨论】:

  • 如果这是 UNIX,您可能会将其编写为 'yes | prorest ...'
  • OutputDataReceived 在收到整行时触发。但是,显然,您的批处理文件没有将换行符放在Do you want to over write it? [y/n]: 行的末尾。
  • Tom - 我确实为删除执行此操作(它总是会提示),但是,对于还原,它更多的是用于错误处理,因为数据库不应该存在,尽管我想要应用程序的选项通过收到提示来安全地响应。
  • PetSerAl - 你是对的 - 有什么方法可以在没有换行符的情况下获得该行?
  • @madlan 您可以编写自己的 Steam 阅读器例程,它将读取并报告不完整的行。我不了解 Visual Basic,所以在这里我无法帮助您。我可以在 C# 上写一些东西,但不确定它是否有帮助。

标签: .net cmd openedge progress-db


【解决方案1】:

您可以编写自己的文本流阅读器例程,它将读取并报告不完整的行。这是一个简单的 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&lt;string&gt; 实例报告它们。它不会用换行符分割字符串,而是将它们保存在字符串中。还有一个测试程序:

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

【讨论】:

    猜你喜欢
    • 2014-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多