Catturare l'output della console da un'applicazione .NET (C #)


130

Come invoco un'applicazione console dalla mia applicazione .NET e acquisisco tutto l'output generato nella console?

(Ricorda, non voglio prima salvare le informazioni in un file e poi ricominciare come mi piacerebbe riceverle dal vivo.)



Si prega di vedere le date su entrambe le domande e vedere quale è "duplicato"
Gripsoft,

"Possibile duplicato" è un modo per ripulire - per chiudere domande simili e mantenerne una con le risposte migliori. La data non è essenziale. Vedi Devo votare per chiudere una domanda duplicata, anche se è molto più recente e ha risposte più aggiornate? Se si accetta che è necessario un chiarimento, si prega di votare Aggiungi link di chiarimento al commento automatizzato "Possibile duplicato"
Michael Freidgeim

Risposte:


163

Questo può essere ottenuto abbastanza facilmente usando la proprietà ProcessStartInfo.RedirectStandardOutput . Un esempio completo è contenuto nella documentazione MSDN collegata; l'unico avvertimento è che potrebbe essere necessario reindirizzare il flusso di errori standard e vedere tutto l'output dell'applicazione.

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
Se non vuoi la nuova linea extra alla fine, usa Console.Writeinvece.
tm1

2
Va notato che se si utilizza ReadToEnd () in combinazione con un'applicazione console che ha la capacità di richiedere all'utente l'input. Ad esempio: Sovrascrivi file: Y o N? ecc. Quindi ReadToEnd può provocare una perdita di memoria, poiché il processo non si chiude mai in attesa dell'input dell'utente. Il modo più sicuro per acquisire l'output è utilizzare il gestore eventi process.OutputDataReceived e consentire al processo di notificare la ricezione dell'applicazione dell'output.
Baaleos,

Come acquisire se nel caso in cui il codice sia distribuito in azzurro webapp, poiché il compilatore.StartInfo.FileName = "csc.exe"; potrebbe non esistere!
Asif Iqbal,

Come acquisire se nel caso in cui il codice sia distribuito in azzurro webapp, poiché il compilatore.StartInfo.FileName = "csc.exe"; potrebbe non esistere!
Asif Iqbal,

37

Questo è un piccolo miglioramento rispetto alla risposta accettata da @mdb . In particolare, acquisiamo anche l'output degli errori del processo. Inoltre, acquisiamo questi output attraverso eventi perché ReadToEnd()non funziona se si desidera catturare sia errori che output regolari. Mi ci è voluto del tempo per farlo funzionare perché in realtà richiede anche BeginxxxReadLine()chiamate dopo Start().

Modo asincrono:

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
Grazie, lo stavo cercando da secoli!
C Bauer,

3
Grazie. Questo è perfetto.
DrFloyd5,

1
Otterrai un posto d'onore nella lista dei ringraziamenti della mia candidatura.
marsh-wiggle,


7

ConsoleAppLauncher è una libreria open source creata appositamente per rispondere a questa domanda. Cattura tutto l'output generato nella console e fornisce un'interfaccia semplice per avviare e chiudere l'applicazione della console.

L'evento ConsoleOutput viene generato ogni volta che una nuova riga viene scritta dalla console nell'output standard / errore. Le linee sono accodate e garantite per seguire l'ordine di uscita.

Disponibile anche come pacchetto NuGet .

Chiamata di esempio per ottenere l'output completo della console:

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

Esempio con feedback dal vivo:

// 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

Ho aggiunto una serie di metodi di supporto alla piattaforma O2 (progetto Open Source) che consentono di creare facilmente un'interazione con un altro processo tramite l'output e l'input della console (vedi http://code.google.com/p/o2platform/ source / browsing / trunk / O2_Scripts / API / Windows / CmdExe / CmdExeAPI.cs )

Utile anche per te potrebbe essere l'API che consente la visualizzazione dell'output della console del processo corrente (in una finestra di controllo o popup esistente). Vedi questo post del blog per maggiori dettagli: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (questo blog contiene anche dettagli su come consumare l'output della console di nuovi processi)


Da allora ho aggiunto più supporto per l'utilizzo di ConsoleOut (in questo caso se avvii il processo .NET da solo). Dai un'occhiata a: Come utilizzare l'output della console nel CPL REPL , aggiungendo "Console Out" a VisualStudio IDE come finestra nativa , Visualizzazione dei messaggi "Console Out" creati all'interno di UserControls
Dinis Cruz

2

Ho realizzato una versione reattiva che accetta callback per stdOut e StdErr.
onStdOute onStdErrvengono chiamati in modo asincrono,
non appena arrivano i dati (prima della chiusura del processo).

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


Esempio di utilizzo

Di seguito verrà eseguito executablecon argse stampare

  • stdOut in bianco
  • stdErr in rosso

alla console.

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

1

Da 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

Aggiunto process.StartInfo.**CreateNoWindow** = true;e 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;
        }
    }
}

Quando lo usi StandardOutput.ReadToEnd(), non tornerà alla prossima istruzione fino alla fine dell'app. quindi il tuo timeout in WaitForExit (timeoutMilliseconds) non funziona! (il tuo codice si bloccherà!)
S.Serpooshan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.