Захоплення консольного виводу з програми .NET (C #)


130

Як я можу викликати консольну програму з мого додатка .NET і захопити весь вихід, отриманий на консолі?

(Пам'ятайте, я не хочу спочатку зберігати інформацію у файлі, а потім репортаж, як я хотів би отримувати її як живу.)



Будь ласка, ознайомтеся з датами обох питань і подивіться, яке з них "дублікат"
Gripsoft

"Можливий дублікат" - це спосіб очищення - закрити подібні запитання та зберегти найкращі відповіді. Дата не є істотною. Див. Чи повинен я голосувати за закриття повторюваного запитання, хоча воно набагато новіше та має більш сучасні відповіді? Якщо ви погоджуєтесь, що це потребує уточнення, будь ласка, проголосуйте за посиланням на роз'яснення до автоматичного коментаря "Можливий дублікат"
Michael Freidgeim

Відповіді:


163

Це може бути досить легко досягти за допомогою властивості ProcessStartInfo.RedirectStandardOutput . Повний зразок міститься в пов'язаній документації MSDN; Єдине застереження полягає в тому, що вам, можливо, доведеться перенаправляти стандартний потік помилок, а також побачити всі результати вашої програми.

Process compiler = new Process();
compiler.StartInfo.FileName = "csc.exe";
compiler.StartInfo.Arguments = "/r:System.dll /out:sample.exe stdstr.cs";
compiler.StartInfo.UseShellExecute = false;
compiler.StartInfo.RedirectStandardOutput = true;
compiler.Start();    

Console.WriteLine(compiler.StandardOutput.ReadToEnd());

compiler.WaitForExit();

3
Якщо ви не хочете зайвого нового рядка в кінці, просто використовуйте Console.Writeзамість цього.
tm1

2
Слід зазначити, що якщо ви використовуєте ReadToEnd () у поєднанні з консольним додатком, який має можливість запросити користувача на введення. Наприклад: Перезаписати файл: Y чи N? Тоді ReadToEnd може призвести до витоку пам’яті, оскільки процес ніколи не закінчується, очікуючи на введення користувача. Більш безпечний спосіб отримання виводу - використовувати обробник подій process.OutputDataReceived і нехай процес сповіщає про вашу заявку на отримання результатів.
Баалеос

Як зафіксувати, якщо в разі розгортання коду до azure webapp, оскільки компілятор.StartInfo.FileName = "csc.exe"; може не існувати!
Асиф Ікбал

Як зафіксувати, якщо в разі розгортання коду до azure webapp, оскільки компілятор.StartInfo.FileName = "csc.exe"; може не існувати!
Асиф Ікбал

37

Це трохи покращення порівняно з прийнятою відповіддю від @mdb . Зокрема, ми також фіксуємо вихід помилок процесу. Крім того, ми фіксуємо ці результати через події, оскільки ReadToEnd()вони не спрацьовують, якщо ви бажаєте фіксувати як помилку, так і звичайний вихід. Мені знадобилось, аби я працював, тому що він також вимагає BeginxxxReadLine()дзвінків після Start().

Асинхронний спосіб:

using System.Diagnostics;

Process process = new Process();

void LaunchProcess()
{
    process.EnableRaisingEvents = true;
    process.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_OutputDataReceived);
    process.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler(process_ErrorDataReceived);
    process.Exited += new System.EventHandler(process_Exited);

    process.StartInfo.FileName = "some.exe";
    process.StartInfo.Arguments = "param1 param2";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardOutput = true;

    process.Start();
    process.BeginErrorReadLine();
    process.BeginOutputReadLine();          

    //below line is optional if we want a blocking call
    //process.WaitForExit();
}

void process_Exited(object sender, EventArgs e)
{
    Console.WriteLine(string.Format("process exited with code {0}\n", process.ExitCode.ToString()));
}

void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine(e.Data + "\n");
}

void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    Console.WriteLine(e.Data + "\n");
}

5
Дякую, шукали це протягом століть!
C Бауер

3
Дякую. Це прекрасно.
DrFloyd5

1
Ви отримаєте почесне місце в списку подяк моєї заяви.
болото-хитання


7

ConsoleAppLauncher - це бібліотека з відкритим кодом, створена спеціально для відповіді на це питання. Він фіксує весь вихід, отриманий на консолі, та забезпечує простий інтерфейс для запуску та закриття консольного додатка.

Подія ConsoleOutput запускається кожного разу, коли консоль записує новий рядок до стандартного виводу / помилки. Рядки в черзі та гарантовано дотримуються порядку виводу.

Також доступний як пакет NuGet .

Зразок виклику, щоб отримати повний вихід консолі:

// Run simplest shell command and return its output.
public static string GetWindowsVersion()
{
    return ConsoleApp.Run("cmd", "/c ver").Output.Trim();
}

Зразок із відгуками:

// Run ping.exe asynchronously and return roundtrip times back to the caller in a callback
public static void PingUrl(string url, Action<string> replyHandler)
{
    var regex = new Regex("(time=|Average = )(?<time>.*?ms)", RegexOptions.Compiled);
    var app = new ConsoleApp("ping", url);
    app.ConsoleOutput += (o, args) =>
    {
        var match = regex.Match(args.Line);
        if (match.Success)
        {
            var roundtripTime = match.Groups["time"].Value;
            replyHandler(roundtripTime);
        }
    };
    app.Run();
}

2

До платформи O2 (проект з відкритим кодом) я додав ряд допоміжних методів, які дозволяють легко скриптувати взаємодію з іншим процесом через консольний вихід та вхід (див. Http://code.google.com/p/o2platform/ source / search / trunk / O2_Scripts / API / Windows / CmdExe / CmdExeAPI.cs )

Також може бути корисним для вас API, який дозволяє переглядати консольний вихід поточного процесу (у наявному вікні управління чи спливаючому вікні). Дивіться цю публікацію в блозі для отримання більш детальної інформації: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (цей блог містить також інформацію про споживання консольний вихід нових процесів)


З тих пір я додав більше підтримки для використання ConsoleOut (у цьому випадку, якщо ви запустите .NET-процес). Подивіться на: Як використовувати висновок консолі в C # реплєї , Додавання «Console Out» в VisualStudio IDE як рідне вікно , Перегляд повідомлення «Console Out» , створені всередині UserControls
Dinis Cruz

2

Я створив реактивну версію, яка приймає зворотні дзвінки для stdOut та StdErr.
onStdOutі onStdErrвикликаються асинхронно,
як тільки дані надходять (до того, як процес закінчується).

public static Int32 RunProcess(String path,
                               String args,
                       Action<String> onStdOut = null,
                       Action<String> onStdErr = null)
    {
        var readStdOut = onStdOut != null;
        var readStdErr = onStdErr != null;

        var process = new Process
        {
            StartInfo =
            {
                FileName = path,
                Arguments = args,
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardOutput = readStdOut,
                RedirectStandardError = readStdErr,
            }
        };

        process.Start();

        if (readStdOut) Task.Run(() => ReadStream(process.StandardOutput, onStdOut));
        if (readStdErr) Task.Run(() => ReadStream(process.StandardError, onStdErr));

        process.WaitForExit();

        return process.ExitCode;
    }

    private static void ReadStream(TextReader textReader, Action<String> callback)
    {
        while (true)
        {
            var line = textReader.ReadLine();
            if (line == null)
                break;

            callback(line);
        }
    }


Приклад використання

Нижче буде працювати executableз argsі друку

  • stdOut у білому кольорі
  • stdErr червоного кольору

до консолі.

RunProcess(
    executable,
    args,
    s => { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(s); },
    s => { Console.ForegroundColor = ConsoleColor.Red;   Console.WriteLine(s); } 
);

1

Від PythonTR - Python Programcıları Derneği, e-kitap, örnek :

Process p = new Process();   // Create new object
p.StartInfo.UseShellExecute = false;  // Do not use shell
p.StartInfo.RedirectStandardOutput = true;   // Redirect output
p.StartInfo.FileName = "c:\\python26\\python.exe";   // Path of our Python compiler
p.StartInfo.Arguments = "c:\\python26\\Hello_C_Python.py";   // Path of the .py to be executed

1

Додано process.StartInfo.**CreateNoWindow** = true;і timeout.

private static void CaptureConsoleAppOutput(string exeName, string arguments, int timeoutMilliseconds, out int exitCode, out string output)
{
    using (Process process = new Process())
    {
        process.StartInfo.FileName = exeName;
        process.StartInfo.Arguments = arguments;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.CreateNoWindow = true;
        process.Start();

        output = process.StandardOutput.ReadToEnd();

        bool exited = process.WaitForExit(timeoutMilliseconds);
        if (exited)
        {
            exitCode = process.ExitCode;
        }
        else
        {
            exitCode = -1;
        }
    }
}

Коли ви користуєтесь, StandardOutput.ReadToEnd()він не повернеться до наступного оператора до кінця програми. тому час очікування в WaitForExit (timeoutMilliseconds) не працює! (ваш код буде висіти!)
S.Serpooshan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.