405 Stimmen

Process.start: Wie erhält man die Ausgabe?

Ich möchte ein externes Befehlszeilenprogramm von meiner Mono/.NET-Anwendung aus ausführen. Zum Beispiel würde ich gerne Folgendes ausführen mencoder . Ist es möglich:

  1. Um die Ausgabe der Kommandozeile zu erhalten und sie in mein Textfeld zu schreiben?
  2. Um den numerischen Wert für die Anzeige eines Fortschrittsbalkens mit der verstrichenen Zeit zu erhalten?

574voto

Ferruccio Punkte 96076

Wenn Sie Ihr Process-Objekt erstellen, legen Sie StartInfo entsprechend fest:

var proc = new Process 
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "program.exe",
        Arguments = "Befehlszeilenargumente für Ihr ausführbares Programm",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

dann starten Sie den Prozess und lesen Sie daraus:

proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    // etwas mit der Zeile machen
}

Sie können int.Parse() oder int.TryParse() verwenden, um die Zeichenfolgen in numerische Werte umzuwandeln. Möglicherweise müssen Sie zuerst einige Zeichenkettenmanipulationen durchführen, wenn ungültige numerische Zeichen in den gelesenen Zeichenfolgen vorhanden sind.

7 Stimmen

Ich habe mich gefragt, wie du mit StandardError umgehen könntest. Übrigens gefällt mir dieses Code-Snippet wirklich gut! Schön und sauber.

3 Stimmen

Vielen Dank, aber ich glaube, ich war nicht klar: Soll ich eine weitere Schleife hinzufügen, um das zu tun?

0 Stimmen

@codea - Ich verstehe. Sie können eine Schleife erstellen, die endet, wenn beide Streams EOF erreichen. Das kann etwas kompliziert werden, weil ein Stream unweigerlich zuerst EOF erreicht und Sie nicht mehr von ihm lesen möchten. Sie könnten auch zwei Schleifen in zwei verschiedenen Threads verwenden.

387voto

T30 Punkte 10166

Sie können Ihre Ausgabe synchron oder asynchron verarbeiten.

1. Synchrone Beispiel

static void runCommand()
{
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR"; // Beachten Sie den /c Befehl (*)
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.Start();
    //* Lesen Sie die Ausgabe (oder den Fehler)
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    string err = process.StandardError.ReadToEnd();
    Console.WriteLine(err);
    process.WaitForExit();
}

Hinweis, dass es besser ist, sowohl Ausgabe als auch Fehler zu verarbeiten: sie müssen getrennt behandelt werden.

(*) Für einige Befehle (hier StartInfo.Arguments) müssen Sie die /c Direktive hinzufügen, sonst friert der Prozess im WaitForExit() ein.

2. Asynchrone Beispiel

static void runCommand() 
{
    //* Erstellen Sie Ihren Prozess
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Setzen Sie Ihre Ausgabe- und Fehler- (asynchrone) Handler
    process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
    process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
    //* Starten Sie den Prozess und die Handler
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit();
}

static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Bearbeiten Sie die Ausgabe (schreiben Sie in Konsole/Log/StringBuilder)
    Console.WriteLine(outLine.Data);
}

Wenn Sie keine komplizierten Operationen mit der Ausgabe durchführen müssen, können Sie die OutputHandler-Methode umgehen, indem Sie die Handler direkt in der Zeile hinzufügen:

//* Setzen Sie Ihre Ausgabe- und Fehler- (asynchrone) Handler
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);

5 Stimmen

Muss async lieben! Ich konnte diesen Code (mit einer kleinen Umschreibung) in VB.net verwenden

0 Stimmen

Bitte beachten Sie, dass 'string output = process.StandardOutput.ReadToEnd();' einen großen String erzeugen kann, wenn viele Zeilen Ausgabe vorhanden sind; das asynchrone Beispiel und die Antwort von Ferruccio verarbeiten die Ausgabe zeilenweise.

10 Stimmen

Hinweis: Ihr erster (synchroner) Ansatz ist nicht korrekt! Sie sollten NICHT sowohl StandardOutput als auch StandardError synchron lesen! Dies führt zu Deadlocks. mindestens einer von ihnen muss asynchron sein.

28voto

cubrman Punkte 880

Gut, für alle, die sowohl Fehler als auch Ausgaben lesen möchten, aber mit einer der Lösungen, die in anderen Antworten (wie bei mir) angegeben sind, Deadlocks haben, hier ist eine Lösung, die ich nach dem Lesen der MSDN-Erklärung für die StandardOutput-Eigenschaft erstellt habe.

Die Antwort basiert auf T30's Code:

static void runCommand()
{
    //* Erstellen Sie Ihren Prozess
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    //* Setzen Sie HIER NUR einen Handler.
    process.ErrorDataReceived += new DataReceivedEventHandler(ErrorOutputHandler);
    //* Starten Sie den Prozess
    process.Start();
    //* Lesen Sie ein Element asynchron
    process.BeginErrorReadLine();
    //* Lesen Sie das andere synchron
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    process.WaitForExit();
}

static void ErrorOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Verarbeiten Sie die Ausgabe (Schreiben in Konsole/Log/StringBuilder)
    Console.WriteLine(outLine.Data);
}

0 Stimmen

Vielen Dank für die Ergänzung. Darf ich fragen, welchen Befehl Sie verwendet haben?

0 Stimmen

Ich entwickle eine App in c#, die darauf ausgelegt ist, ein mysqldump.exe zu starten, dem Benutzer jede einzelne Nachricht anzuzeigen, die die App generiert, auf das Ende zu warten und dann weitere Aufgaben auszuführen. Ich kann nicht verstehen, um welche Art von Befehl es geht, von dem Sie sprechen? Diese gesamte Frage bezieht sich darauf, einen Prozess aus c# heraus zu starten.

1 Stimmen

Wenn Sie zwei separate Handler verwenden, treten keine Deadlocks auf.

10voto

driis Punkte 156110

Die standardmäßige .NET-Methode, dies zu tun, besteht darin, aus dem StandardOutput-Stream des Prozesses zu lesen. Ein Beispiel hierzu finden Sie in der verknüpften MSDN-Dokumentation. Ebenso können Sie aus dem StandardError lesen und in StandardInput schreiben.

6voto

basarat Punkte 230827
  1. Es ist möglich, die Ausgabe der Befehlszeilenshell eines Prozesses wie hier beschrieben zu erhalten: http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx

  2. Dies hängt von mencoder ab. Wenn es diesen Status in der Befehlszeile ausgibt, dann ja :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X