Может ли System.Diagnostic перенаправлять вывод при получении какой-либо строки, а не в конце строки? - PullRequest
3 голосов
/ 19 октября 2011

Можно ли получить выходные данные из System.Diagnostic.Process, когда ... происходит, а не в конце строки?На данный момент у меня есть

    psi.RedirectStandardOutput = true;
    psi.RedirectStandardError = true;
    psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
    psi.UseShellExecute = false;

    reg = System.Diagnostics.Process.Start(psi);

    reg.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
    reg.BeginOutputReadLine();  

. Как видите, вызов BeginOutputReadLine позволяет мне читать (перенаправленный) вывод только тогда, когда найдена конечная строка .Существует ли такой же метод, но который вызывает делегат «когда процесс отправляет какой-либо символ на вывод»?

Спасибо

Ответы [ 2 ]

4 голосов
/ 26 октября 2011

Краткий ответ: нет, есть такой метод на Процесс , который делает то, что вам нужно.

Длинный ответ: да, вы, похоже, можете это сделать, но этопотребует от вас гораздо больше работы.

(Тем не менее, как говорит Ганс Пассант, это также зависит от другого процесса раннего сброса. Если это не так, вам ничего не поможет.)

Метод 1 (жесткий)

BeginOutputReadLine , по-видимому, создает синхронизированную оболочку вокруг фактического базового Stream.BeginRead метода, обеспечивая егобуферизует достаточно данных и вызывает ваш обработчик OutputDataReceived .(И на самом деле это довольно много работы, чтобы дать вам полные строки, а не куски, не говоря уже о синхронизированной диспетчеризации событий, из того, что я вижу с помощью ILSpy.)

Так что вы можете попытаться вызвать StandardOutput.BaseStream.BeginRead напрямую, пропуская OutputDataReceived и BeginOutputReadLine полностью, поэтому вы можете получать чанки по мере их поступления.

К сожалению,это означает, что вам нужно выполнить кодирование самостоятельно (поскольку потоки работают с байтами, а не с символами, а StandardOutput.CurrentEncoding обеспечивает основную часть этой поддержки), вам нужно будет выполнить все асинхронные операции чтения самостоятельно.( Stream.BeginRead - это не очень приятный API для работы), и вам придется самостоятельно выполнять синхронизацию.

Очень весело (и много шансов ошибиться).

Метод 2 (проще), почти асинхронный

Вы также можете читать из StandardOutput синхронно uпеть StandardOutput.Читать .Если вы не хотите блокировать, вы можете раскрутить другой поток или использовать TaskFactory.StartNew :

var readTask = TaskFactory.StartNew(() => {
    try
    {
        while ((int c = process.StandardOutput.Read()) != -1) 
        {
           ...
        }
    }
    catch
    {
        // don't want to kill the process if something goes wrong above;
        // uncaught exceptions on background threads do that.
    }
});

И затем в тот момент, когда вы хотите быть уверенным, что чтение завершено,вы говорите

readTask.Wait();
3 голосов
/ 26 октября 2011

Казалось бы, асинхронные методы / события не позволяют вам читать одиночные символы из вывода (только полные строки, как подсказывают названия методов).

Следующий код делает то, что вы хотите,но синхронно:

class Program
{
    public static bool Exit = false;
    static void Main(string[] args)
    {
        var p = new Process
                    {
                        StartInfo =
                            {
                                FileName = @"program-not-outputting-newlines",
                                Arguments = "test",
                                UseShellExecute = false,
                                RedirectStandardOutput = true
                            },
                        EnableRaisingEvents = true
                    };
        p.Start();
        var s = p.StandardOutput;
        p.Exited += (sender, e) => Exit = true;

        while(!Exit)
        {
            Console.Write((char) s.Read());
        }
        Console.Read();
    }
}

Кажется, что вызов s.Read () блокирует текущий поток (даже несмотря на то, что существует версия ReadBlock () - docwriter, вероятно, неправильно понял), поэтомуВы можете захотеть сделать это в отдельном потоке и сделать некоторую собственную передачу сообщений / сбор событий, чтобы сделать ее асинхронной.

Программа, с которой я тестировал, была простым циклом, выводящим целые числа от 0 до 10 со случайными интервалами,без перевода строки и вызовов Console.Out.Flush для каждой записи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...