397 votes

Process.start : comment obtenir la sortie ?

Je voudrais exécuter un programme externe en ligne de commande à partir de mon application Mono/.NET. Par exemple, je voudrais exécuter mencoder . C'est possible :

  1. Pour obtenir la sortie du shell de la ligne de commande et l'écrire dans ma zone de texte ?
  2. Pour obtenir la valeur numérique afin d'afficher une barre de progression avec le temps écoulé ?

6voto

basarat Points 22425
  1. Il est possible d'obtenir la sortie de l'interpréteur de commandes d'un processus comme décrit ici : http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx

  2. Cela dépend de mencoder. S'il affiche ce statut sur la ligne de commande, alors oui :)

3voto

SHUBHAM PATIDAR Points 31

Vous pouvez enregistrer la sortie du processus en utilisant le code ci-dessous :

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

2voto

Comment lancer un processus (tel qu'un fichier bat, perl script, programme console) et faire afficher sa sortie standard sur un formulaire Windows :

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

Vous pouvez trouver ProcessCaller sur ce lien : Lancement d'un processus et affichage de sa sortie standard

2voto

Jason Harris Points 306

Je me heurtais au fameux problème de blocage en appelant Process.StandardOutput.ReadLine et Process.StandardOutput.ReadToEnd .

Mon objectif et mon cas d'utilisation sont simples. Lancer un processus et rediriger sa sortie afin que je puisse capturer cette sortie et l'enregistrer dans la console via l'outil .NET Core ILogger<T> et également ajouter la sortie redirigée à un fichier journal.

Voici ma solution en utilisant les gestionnaires d'événements asynchrones intégrés. Process.OutputDataReceived et Process.ErrorDataReceived .

var p = new Process
{
    StartInfo = new ProcessStartInfo(
        command.FileName, command.Arguments
    )
    {
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        UseShellExecute = false,
    }
};

// Asynchronously pushes StdOut and StdErr lines to a thread safe FIFO queue
var logQueue = new ConcurrentQueue<string>();
p.OutputDataReceived += (sender, args) => logQueue.Enqueue(args.Data);
p.ErrorDataReceived += (sender, args) => logQueue.Enqueue(args.Data);

// Start the process and begin streaming StdOut/StdErr
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();

// Loop until the process has exited or the CancellationToken is triggered
do
{
    var lines = new List<string>();
    while (logQueue.TryDequeue(out var log))
    {
        lines.Add(log);
        _logger.LogInformation(log)
    }
    File.AppendAllLines(_logFilePath, lines);

    // Asynchronously sleep for some time
    try
    {
        Task.Delay(5000, stoppingToken).Wait(stoppingToken);
    }
    catch(OperationCanceledException) {}

} while (!p.HasExited && !stoppingToken.IsCancellationRequested);

2voto

Tyrrrz Points 438

System.Diagnostics.Process n'est pas le plus agréable à travailler, vous pouvez donc essayer de CliWrap . Il offre de nombreux modèles différents pour travailler avec la sortie, y compris la tuyauterie, la mise en mémoire tampon et le streaming en temps réel. Voici quelques exemples (tirés du fichier readme).

Il suffit de lancer un exécutable en ligne de commande :

using CliWrap;

var result = await Cli.Wrap("path/to/exe")
    .WithArguments("--foo bar")
    .WithWorkingDirectory("work/dir/path")
    .ExecuteAsync();

// Result contains:
// -- result.ExitCode        (int)
// -- result.StartTime       (DateTimeOffset)
// -- result.ExitTime        (DateTimeOffset)
// -- result.RunTime         (TimeSpan)

Lance un exécutable en ligne de commande et met en mémoire tampon stdout/stderr :

using CliWrap;
using CliWrap.Buffered;

// Calling `ExecuteBufferedAsync()` instead of `ExecuteAsync()`
// implicitly configures pipes that write to in-memory buffers.
var result = await Cli.Wrap("path/to/exe")
    .WithArguments("--foo bar")
    .WithWorkingDirectory("work/dir/path")
    .ExecuteBufferedAsync();

// Result contains:
// -- result.StandardOutput  (string)
// -- result.StandardError   (string)
// -- result.ExitCode        (int)
// -- result.StartTime       (DateTimeOffset)
// -- result.ExitTime        (DateTimeOffset)
// -- result.RunTime         (TimeSpan)

Lancer un exécutable en ligne de commande avec une configuration manuelle des tuyaux :

using CliWrap

var buffer = new StringBuilder();

var result = await Cli.Wrap("foo")
    .WithStandardOutputPipe(PipeTarget.ToFile("output.txt"))
    .WithStandardErrorPipe(PipeTarget.ToStringBuilder(buffer))
    .ExecuteAsync();

Lance un exécutable de ligne de commande en tant que flux d'événements :

using CliWrap;
using CliWrap.EventStream;

var cmd = Cli.Wrap("foo").WithArguments("bar");

await foreach (var cmdEvent in cmd.ListenAsync())
{
    switch (cmdEvent)
    {
        case StartedCommandEvent started:
            _output.WriteLine($"Process started; ID: {started.ProcessId}");
            break;
        case StandardOutputCommandEvent stdOut:
            _output.WriteLine($"Out> {stdOut.Text}");
            break;
        case StandardErrorCommandEvent stdErr:
            _output.WriteLine($"Err> {stdErr.Text}");
            break;
        case ExitedCommandEvent exited:
            _output.WriteLine($"Process exited; Code: {exited.ExitCode}");
            break;
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X