2015-11-21 1 views
0

Я асинхронно читаю вывод из командного файла после запуска его с некоторыми параметрами. Если командный файл ожидает ввода - текст запроса на ввод не перенаправляется - если процесс не завершен (что, очевидно, слишком поздно для ответа).Асинхронно считывает вывод cmd в .NET. - Висит на запрос ввода процесса.

Если выполняется в стандартном окне 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 
+0

Если бы это был UNIX, вы, вероятно, использовали бы его как «да». prorest ... ' –

+1

'OutputDataReceived' срабатывает при получении полной строки. Но, судя по всему, ваш пакетный файл не ставит новый символ линии в конце 'Вы хотите написать? [y/n]: 'строка. – PetSerAl

+0

Tom - я делаю именно это для удаления (всегда будет запрашивать), однако для восстановления это больше подходит для обработки ошибок, поскольку база данных не должна существовать, хотя я бы хотел, чтобы приложение для безопасного ответа получило приглашение , – madlan

ответ

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