it-swarm.com.de

Process.start: Wie erhalte ich die Ausgabe?

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

  1. Um die Befehlszeilen-Shell-Ausgabe zu erhalten und sie in mein Textfeld zu schreiben?
  2. Um den numerischen Wert zu erhalten, um eine Fortschrittsleiste mit abgelaufener Zeit anzuzeigen?
243
stighy

Wenn Sie Ihre Process-Objektgruppe StartInfo entsprechend erstellen:

var proc = new Process 
{
    StartInfo = new ProcessStartInfo
    {
        FileName = "program.exe",
        Arguments = "command line arguments to your executable",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

starten Sie dann den Prozess und lesen Sie daraus:

proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    // do something with line
}

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

372
Ferruccio

Sie können Ihre Ausgabe synchron oder asynchron verarbeiten.

1: Synchrones Beispiel

static void runCommand()
{
    Process process = new Process();
    process.StartInfo.FileName = "cmd.exe";
    process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*)
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;
    process.Start();
    //* Read the output (or the error)
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    string err = process.StandardError.ReadToEnd();
    Console.WriteLine(err);
    process.WaitForExit();
}

Hinweis, dass es besser ist, sowohl output als auch error zu verarbeiten: Sie müssen separat behandelt werden.

(*) Für einige Befehle (hier StartInfo.Arguments) müssen Sie den /cDirektive hinzufügen, ansonsten friert der Prozess in der WaitForExit().

2: Asynchrones Beispiel

static void runCommand() 
{
    //* Create your Process
    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;
    //* Set your output and error (asynchronous) handlers
    process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
    process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
    //* Start process and handlers
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit();
}

static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/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 inline hinzufügen:

//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
195
T30

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

Die Antwort basiert auf dem Code von T30:

static void runCommand()
{
    //* Create your Process
    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;
    //* Set ONLY ONE handler here.
    process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
    //* Start process
    process.Start();
    //* Read one element asynchronously
    process.BeginErrorReadLine();
    //* Read the other one synchronously
    string output = process.StandardOutput.ReadToEnd();
    Console.WriteLine(output);
    process.WaitForExit();
}

static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}
8
cubrman

Die Standardmethode von .NET ist das Lesen aus dem Process ' StandardOutput - Stream. In den verknüpften MSDN-Dokumenten finden Sie ein Beispiel. Ähnlich können Sie von StandardError lesen und in StandardInput schreiben.

7
driis

sie können den gemeinsam genutzten Speicher für die beiden Prozesse verwenden, um durch zu kommunizieren, auschecken MemoryMappedFile

sie erstellen hauptsächlich eine mit dem Speicher verknüpfte Datei mmf im übergeordneten Prozess mithilfe der "using" -Anweisung. Dann erstellen Sie den zweiten Prozess bis zum Abschluss und lassen das Ergebnis mit mmf in die BinaryWriter schreiben Lesen Sie dann das Ergebnis von mmf mit dem übergeordneten Prozess. Sie können den Namen mmf auch mit Befehlszeilenargumenten oder mit einem harten Code übergeben.

vergewissern Sie sich bei der Verwendung der zugeordneten Datei im übergeordneten Prozess, dass der untergeordnete Prozess das Ergebnis in die zugeordnete Datei schreibt, bevor die zugeordnete Datei im übergeordneten Prozess freigegeben wird

Beispiel: Übergeordneter Prozess

    private static void Main(string[] args)
    {
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("memfile", 128))
        {
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(512);
            }

            Console.WriteLine("Starting the child process");
            // Command line args are separated by a space
            Process p = Process.Start("ChildProcess.exe", "memfile");

            Console.WriteLine("Waiting child to die");

            p.WaitForExit();
            Console.WriteLine("Child died");

            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("Result:" + reader.ReadInt32());
            }
        }
        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }

Kindprozess 

    private static void Main(string[] args)
    {
        Console.WriteLine("Child process started");
        string mmfName = args[0];

        using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(mmfName))
        {
            int readValue;
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("child reading: " + (readValue = reader.ReadInt32()));
            }
            using (MemoryMappedViewStream input = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(input);
                writer.Write(readValue * 2);
            }
        }

        Console.WriteLine("Press any key to continue...");
        Console.ReadKey();
    }

um dieses Beispiel verwenden zu können, müssen Sie eine Lösung mit zwei Projekten erstellen. Dann nehmen Sie das Build-Ergebnis des untergeordneten Prozesses aus% childDir%/bin/debug und kopieren es in% parentDirectory%/bin/debug übergeordnetes Projekt

childDir und parentDirectory sind die Ordnernamen Ihrer Projekte auf dem PC Viel Glück :)

4
shakram02
  1. Die Befehlszeilen-Shell-Ausgabe eines Prozesses kann wie folgt abgerufen werden: http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx

  2. Dies hängt vom Mencoder ab. Wenn dieser Status in der Befehlszeile ausgegeben wird, dann ja :)

3
basarat

So starten Sie einen Prozess (z. B. eine bat-Datei, ein Perl-Skript, ein Konsolenprogramm) und lassen dessen Standardausgabe in einem Windows-Formular anzeigen

processCaller = new ProcessCaller(this);
//processCaller.FileName = @"..\..\hello.bat";
processCaller.FileName = @"commandline.exe";
processCaller.Arguments = "";
processCaller.StdErrReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.StdOutReceived += new DataReceivedHandler(writeStreamInfo);
processCaller.Completed += new EventHandler(processCompletedOrCanceled);
processCaller.Cancelled += new EventHandler(processCompletedOrCanceled);
// processCaller.Failed += no event handler for this one, yet.

this.richTextBox1.Text = "Started function.  Please stand by.." + Environment.NewLine;

// the following function starts a process and returns immediately,
// thus allowing the form to stay responsive.
processCaller.Start();    

Sie finden ProcessCaller unter diesem Link: Prozess starten und Standardausgabe anzeigen

1

Sie können die Prozessausgabe mit dem folgenden Code protokollieren:

ProcessStartInfo pinfo = new ProcessStartInfo(item);
pinfo.CreateNoWindow = false;
pinfo.UseShellExecute = true;
pinfo.RedirectStandardOutput = true;
pinfo.RedirectStandardInput = true;
pinfo.RedirectStandardError = true;
pinfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
var p = Process.Start(pinfo);
p.WaitForExit();
Process process = Process.Start(new ProcessStartInfo((item + '>' + item + ".txt"))
{
    UseShellExecute = false,
    RedirectStandardOutput = true
});
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
if (process.ExitCode != 0) { 
}
0
SHUBHAM PATIDAR