У меня есть следующий код:
info = new System.Diagnostics.ProcessStartInfo("TheProgram.exe", String.Join(" ", args));
info.CreateNoWindow = true;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForExit();
Console.WriteLine(p.StandardOutput.ReadToEnd()); //need the StandardOutput contents
Я знаю, что вывод от запускаемого мной процесса составляет около 7 МБ. Запуск его в консоли Windows работает нормально. К сожалению, программно это висит неопределенно в WaitForExit. Также обратите внимание, что код НЕ зависает для небольших выходов (например, 3 КБ).
Возможно ли, что внутренний StandardOutput в ProcessStartInfo не может буферизовать 7 МБ? Если так, что я должен сделать вместо этого? Если нет, что я делаю не так?
c#
processstartinfo
Epaga
источник
источник
Ответы:
Проблема в том, что если вы перенаправляете
StandardOutput
и / илиStandardError
внутренний буфер может заполниться. Какой бы порядок вы ни использовали, могут возникнуть проблемы:StandardOutput
процесс может заблокировать попытки записи в него, поэтому процесс никогда не завершится.StandardOutput
использованием ReadToEnd, тогда ваш процесс может заблокироваться, если процесс никогда не закрываетсяStandardOutput
(например, если он никогда не завершается или если он заблокирован при записиStandardError
).Решение состоит в том, чтобы использовать асинхронное чтение, чтобы гарантировать, что буфер не переполняется. Для того, чтобы избежать каких - либо тупики и собрать всю выход из обоих
StandardOutput
иStandardError
вы можете сделать это:РЕДАКТИРОВАТЬ: См. Ответы ниже, чтобы узнать, как избежать исключения ObjectDisposedException, если истекло время ожидания.
источник
using
заявления для обработчиков событий должны быть выше вusing
заявлении для самого процесса?Документация для
Process.StandardOutput
говорит прочитать , прежде чем ждать , в противном случае вы можете тупиковой, фрагмент кода скопирован ниже:источник
RedirectStandardOutput = true;
и не используете,p.StandardOutput.ReadToEnd();
вы получаете тупик / зависание.Ответ Марка Байерса отличный, но я бы добавил следующее:
OutputDataReceived
ИErrorDataReceived
делегаты должны быть удалены до того , какoutputWaitHandle
иerrorWaitHandle
получить расположены. Если процесс продолжает выводить данные после того, как тайм - аут был превышен , а затем завершается,outputWaitHandle
иerrorWaitHandle
переменные будут доступны после того , как расположены.(К вашему сведению, я должен был добавить это предостережение в качестве ответа, поскольку не мог прокомментировать его сообщение.)
источник
Это более современное ожидаемое решение на основе параллельной библиотеки задач (TPL) для .NET 4.5 и выше.
Пример использования
Реализация
источник
Проблема с необработанным исключением ObjectDisposedException возникает, когда время ожидания истекло. В таком случае другие части условия:
не выполнены. Я решил эту проблему следующим образом:
источник
output
иerror
наoutputBuilder
? Может кто-нибудь дать полный ответ, который работает?Роб ответил на это и спас мне еще несколько часов испытаний. Прочитайте буфер вывода / ошибок перед ожиданием:
источник
WaitForExit()
?ReadToEnd
или подобные методы (напримерStandardOutput.BaseStream.CopyTo
), вернутся после того, как ВСЕ данные прочитаны. после этого ничего неУ нас также есть этот вопрос (или вариант).
Попробуйте следующее:
1) Добавить тайм-аут в p.WaitForExit (nnnn); где nnnn в миллисекундах.
2) Поместите вызов ReadToEnd перед вызовом WaitForExit. Это является то , что мы уже видели MS рекомендую.
источник
Кредит EM0 для https://stackoverflow.com/a/17600012/4151626
Другие решения (в том числе EM0) все еще заблокированы для моего приложения из-за внутренних тайм-аутов и использования StandardOutput и StandardError порожденным приложением. Вот что сработало для меня:
Редактировать: добавлена инициализация StartInfo к примеру кода
источник
Я решил это так:
Я перенаправил как ввод, вывод и ошибку, так и обработал чтение из потока вывода и ошибок. Это решение работает для SDK 7- 8.1, как для Windows 7, так и для Windows 8
источник
Я попытался создать класс, который бы решал вашу проблему, используя асинхронное чтение потока, принимая во внимание ответы Марка Байерса, Роба Стивейя. При этом я понял, что существует ошибка, связанная с чтением потока вывода асинхронного процесса.
Я сообщил об этой ошибке в Microsoft: https://connect.microsoft.com/VisualStudio/feedback/details/3119134
Резюме:
Вам, вероятно, лучше использовать асинхронное чтение, как предложили другие пользователи для вашего случая. Но вы должны знать, что вы можете пропустить некоторую информацию из-за состояния гонки.
источник
Я считаю, что это простой и лучший подход (нам не нужен
AutoResetEvent
):источник
.FileName = Path + @"\ggsci.exe" + @" < obeycommand.txt"
упростить свой код? Или, может быть, что-то эквивалентное,"echo command | " + Path + @"\ggsci.exe"
если вы действительно не хотите использовать отдельный файл obeycommand.txt.Ни один из ответов выше не делает работу.
Решение Роба зависает, и решение «Марк Байерс» получает исключение (я попробовал «решения» других ответов).
Поэтому я решил предложить другое решение:
Этот код отлажен и работает отлично.
источник
GetProcessOutputWithTimeout
метода.Введение
В настоящее время принятый ответ не работает (выдает исключение), и существует слишком много обходных путей, но нет полного кода. Это, очевидно, тратит много времени людей, потому что это популярный вопрос.
Комбинируя ответ Марка Байерса и ответ Кароля Тила, я написал полный код, основанный на том, как я хочу использовать метод Process.Start.
использование
Я использовал его для создания диалога прогресса вокруг команд git. Вот как я это использовал:
Теоретически вы также можете комбинировать stdout и stderr, но я этого не проверял.
Код
источник
Я знаю, что это старый ужин, но после прочтения всей этой страницы ни одно из решений не сработало для меня, хотя я не пробовал Мухаммеда Рехана, так как код был немного сложным, хотя, думаю, он был на правильном пути , Когда я говорю, что это не работает, это не совсем верно, иногда это будет работать нормально, я думаю, это как-то связано с длиной вывода до знака EOF.
В любом случае, решение, которое работало для меня, состояло в том, чтобы использовать разные потоки для чтения StandardOutput и StandardError и записи сообщений.
Надеюсь, что это поможет кому-то, кто думал, что это может быть так сложно!
источник
sw.FlushAsync(): Object is not set to an instance of an object. sw is null.
как / где должноsw
быть определено?Прочитав все посты здесь, я остановился на консолидированном решении Марко Авлияша. тем не мение , это не решило все мои проблемы.
В нашей среде у нас есть служба Windows, которая планирует запускать сотни различных файлов .bat .cmd .exe, ... и т. Д., Которые накапливались годами и были написаны многими разными людьми и в разных стилях. Мы не контролируем написание программ и сценариев, мы просто несем ответственность за планирование, запуск и отчетность об успехах / неудачах.
Итак, я попробовал почти все предложения здесь с разным уровнем успеха. Ответ Марко был почти идеальным, но при запуске в качестве службы он не всегда захватывал стандартный вывод. Я так и не понял, почему нет.
Единственное найденное нами решение, которое работает во ВСЕХ наших случаях, это: http://csharptest.net/319/using-the-processrunner-class/index.html
источник
Обходной путь, который я использовал, чтобы избежать всей сложности:
Поэтому я создаю временный файл, перенаправляю на него вывод и ошибку с помощью,
> outputfile > 2>&1
а затем просто читаю файл после завершения процесса.Другие решения хороши для сценариев, в которых вы хотите делать другие вещи с выводом, но для простых вещей это позволяет избежать большой сложности.
источник
Я прочитал много ответов и сделал свой. Не уверен, что это исправит в любом случае, но это исправляет в моей среде. Я просто не использую WaitForExit и использую WaitHandle.WaitAll как для выходных сигналов, так и для сигналов об ошибках. Я буду рад, если кто-то увидит возможные проблемы с этим. Или если это кому-то поможет. Для меня это лучше, потому что не использует таймауты.
источник
Я думаю, что с асинхронным, возможно иметь более элегантное решение и не иметь взаимоблокировок даже при использовании как standardOutput, так и standardError:
Это основано на ответе Марк Байерс. Если вы не используете асинхронный метод, вы можете использовать
string output = tStandardOutput.result;
вместоawait
источник
Ни один из этих ответов не помог мне, но это решение хорошо работало с обработкой зависаний
https://stackoverflow.com/a/60355879/10522960
источник
Это сообщение может быть устаревшим, но я выяснил, что основная причина, почему он обычно зависает, связана с переполнением стека для redirectStandardoutput или если у вас есть redirectStandarderror.
Поскольку выходные данные или данные об ошибках велики, это приведет к зависанию, так как оно все еще обрабатывается в течение неопределенного времени.
Итак, чтобы решить эту проблему:
источник
Давайте назовем пример кода, размещенный здесь, перенаправителем, а другую программу - перенаправленной. Если бы это был я, я бы написал тестовую перенаправленную программу, которую можно использовать для дублирования проблемы.
Так я и сделал. Для тестовых данных я использовал спецификацию языка ECMA-334 C # v PDF; это около 5 МБ. Следующее является важной частью этого.
Значение размера данных не соответствует фактическому размеру файла, но это не имеет значения. Неясно, всегда ли PDF-файл использует CR и LF в конце строк, но это не имеет значения для этого. Вы можете использовать любой другой большой текстовый файл для тестирования.
Использование этого примера кода перенаправителя зависает, когда я пишу большой объем данных, но не когда я пишу небольшой объем.
Я очень старался как-то отследить выполнение этого кода и не смог. Я закомментировал строки перенаправленной программы, которая отключила создание консоли для перенаправленной программы, чтобы попытаться получить отдельное окно консоли, но я не смог.
Затем я нашел, как запустить консольное приложение в новом окне, родительском окне или без окна . Таким образом, очевидно, что мы не можем (легко) иметь отдельную консоль, когда одна консольная программа запускает другую консольную программу без ShellExecute, и поскольку ShellExecute не поддерживает перенаправление, мы должны совместно использовать консоль, даже если мы не указываем окно для другого процесса.
Я предполагаю, что если перенаправленная программа заполняет буфер где-то, то она должна ждать, пока данные будут прочитаны, и если в этот момент данные не будут прочитаны перенаправителем, то это тупик.
Решение состоит в том, чтобы не использовать ReadToEnd и читать данные во время записи данных, но нет необходимости использовать асинхронное чтение. Решение может быть довольно простым. Следующее работает для меня с 5 МБ PDF.
Другая возможность - использовать программу с графическим интерфейсом для перенаправления. Предыдущий код работает в приложении WPF, за исключением явных изменений.
источник
У меня была та же проблема, но причина была в другом. Однако это произошло бы в Windows 8, но не в Windows 7. Кажется, следующая строка вызвала проблему.
Решением было НЕ отключить UseShellExecute. Теперь я получил всплывающее окно Shell, которое нежелательно, но гораздо лучше, чем программа, ожидающая ничего особенного. Поэтому я добавил следующие обходные пути для этого:
Теперь единственное, что меня беспокоит, это то, почему это происходит в первую очередь под Windows 8.
источник
UseShellExecute
установить значение false, если вы хотите перенаправить вывод.