Process.Start: wie die Ausgabe zu bekommen?
-
28-09-2019 - |
Frage
Ich möchte ein externes Kommandozeilen-Programm von meinem Mono / .NET App auszuführen. Zum Beispiel würde Ich mag laufen mencoder . Ist es möglich:
- Um die Befehlszeilen-Shell Ausgabe zu erhalten, und schreiben Sie es auf meinem Textfeld?
- , um den Zahlenwert zu erhalten, einen Fortschrittsbalken zu zeigen, mit der Zeit vergangen ist?
Lösung
Wenn Sie erstellen Ihre Process
Objektsatz StartInfo
entsprechend:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "program.exe",
Arguments = "command line arguments to your executable",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
dann den Prozess starten und liest 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 Strings in numerische Werte umzuwandeln. Sie können einige String-Manipulation zu tun haben, zuerst, wenn es ungültige numerische Zeichen in den Streichern sind Sie lesen.
Andere Tipps
Sie können die Ausgabe verarbeiten synchron oder asynchron .
1: Synchrone 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, beide zu verarbeiten Ausgang und Fehler : Sie müssen separat behandelt werden
. (*) Für einige Befehle (hier StartInfo.Arguments
) müssen Sie die /c
hinzufügen Richtlinie , sonst der Prozess gefriert in der WaitForExit()
.
2: Asynchronous 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 nicht brauchen, komplizierte Operationen mit dem Ausgang zu tun, können Sie Bypass der Output-Methode, nur die Handler hinzugefügt direkt inline:
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
In Ordnung, für jeden, den beiden Fehler und Ausgänge lesen, aber bekommt Deadlocks mit einem der Lösungen, in anderen Antworten zur Verfügung gestellt (wie ich), hier ist eine Lösung, dass ich nach dem Lesen MSDN Erklärung für StandardOutput Eigenschaft gebaut.
Antwort basiert auf T30 Code:
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);
}
Der Standard-.NET-Weg, dies zu tun, ist aus dem Prozess lesen StandardOutput Stream. Es gibt ein Beispiel in der verknüpften MSDN-Dokumentation. Ähnliche, können Sie lesen von Standarderror und schreiben auf StandardInput .
-
Es ist möglich, den Befehlszeilen-Shell Ausgang eines Prozesses zu erhalten, wie hier beschrieben: http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx
-
Dies ist abhängig von mencoder. Wenn es diesen Status in der Befehlszeile ouputs dann ja:)
können Sie verwenden den gemeinsamen Speicher für die 2-Prozesse bis hin zu kommunizieren Besuche MemoryMappedFile
Sie werden in erster Linie eine Memory-Mapped-Datei mmf
in dem übergeordneten Prozess erstellen mit „using“ Anweisung dann den zweiten Prozess erstellen, bis es beendet und lassen Sie es das Ergebnis an den mmf
schreibt BinaryWriter
verwenden, lesen Sie dann das Ergebnis aus dem mmf
mit der übergeordnete Prozess, können Sie auch den Namen mmf
Befehlszeilenargumente oder Fest Code übergeben Sie es.
stellen Sie sicher, wenn die zugeordnete Datei in dem übergeordneten Prozess mit, dass Sie dem Kind Prozess schreibt das Ergebnis in die zugeordnete Datei, bevor die abgebildete Datei im übergeordneten Prozess freigegeben wird
Beispiel: Eltern-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();
}
Child Prozess
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();
}
Mit dieser Probe verwenden, müssen Sie in eine Lösung mit 2-Projekte erstellen, dann nehmen Sie die Build-Ergebnis des Kindes Prozess von% childDir% / bin / debug und kopieren Sie sie in% Parent% / bin / debug läuft dann das übergeordnete Projekt
childDir
und parentDirectory
sind die Ordnernamen Ihrer Projekte auf dem PC
Glück:)
Wie ein Verfahren (wie eine Fledermaus-Datei, Perl-Skript, Konsolenprogramm) starten und haben die Standardausgabe auf einem Fenster angezeigt bilden:
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 können ProcessCaller
finden auf diesen Link: einen Prozess starten und die Standardausgabe Anzeige
Die Lösung, die für mich in Win und Linux gearbeitet ist die folgende
// GET api/values
[HttpGet("cifrado/{xml}")]
public ActionResult<IEnumerable<string>> Cifrado(String xml)
{
String nombreXML = DateTime.Now.ToString("ddMMyyyyhhmmss").ToString();
String archivo = "/app/files/"+nombreXML + ".XML";
String comando = " --armor --recipient bibankingprd@bi.com.gt --encrypt " + archivo;
try{
System.IO.File.WriteAllText(archivo, xml);
//String comando = "C:\\GnuPG\\bin\\gpg.exe --recipient licorera@local.com --armor --encrypt C:\\Users\\Administrador\\Documents\\pruebas\\nuevo.xml ";
ProcessStartInfo startInfo = new ProcessStartInfo() {FileName = "/usr/bin/gpg", Arguments = comando };
Process proc = new Process() { StartInfo = startInfo, };
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.Start();
proc.WaitForExit();
Console.WriteLine(proc.StandardOutput.ReadToEnd());
return new string[] { "Archivo encriptado", archivo + " - "+ comando};
}catch (Exception exception){
return new string[] { archivo, "exception: "+exception.ToString() + " - "+ comando };
}
}
Sie können Prozessausgangs melde dich hier unten Code verwendet:
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) {
}