Process.start: как получить вывод? - PullRequest
264 голосов
/ 27 ноября 2010

Я хотел бы запустить внешнюю программу командной строки из моего приложения Mono / .NET. Например, я хотел бы запустить mencoder . Возможно ли это:

  1. Чтобы получить вывод оболочки командной строки и записать его в мое текстовое поле?
  2. Чтобы получить числовое значение для отображения индикатора выполнения по истечении времени?

Ответы [ 8 ]

404 голосов
/ 27 ноября 2010

Когда вы создаете Process объект, установите StartInfo соответственно:

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

затем запустите процесс и прочитайте с него:

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

Вы можете использовать int.Parse() или int.TryParse() для преобразования строк в числовые значения. Возможно, вам придется сначала выполнить некоторые операции со строками, если в прочитанных строках есть недопустимые числовые символы.

213 голосов
/ 20 апреля 2015

Вы можете обработать ваш вывод синхронно или асинхронно .

1: синхронный пример

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

Обратите внимание , что лучше обрабатывать как вывод , так и ошибки : они должны обрабатываться отдельно.

(*) Для некоторых команд (здесь StartInfo.Arguments) необходимо добавить директиву /c , в противном случае процесс останавливается в WaitForExit().

2: асинхронный пример

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

Если вам не нужно усложнять операции с выводом, вы можете обойти метод OutputHandler, просто добавив обработчики прямо в строку:

//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
9 голосов
/ 10 мая 2016

Хорошо, для тех, кто хочет прочитать ошибки и выходы, но получает взаимные блокировки с любым из решений, представленных в других ответах (например, я), вот решение, которое я построил после прочтения пояснения MSDN для свойства StandardOutput.

Ответ основан на коде 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);
}
7 голосов
/ 27 ноября 2010

Стандартный способ .NET сделать это - прочитать из потока Process StandardOutput . Есть пример в связанных документах MSDN. Аналогично, вы можете читать из StandardError и записывать в StandardInput .

4 голосов
/ 29 апреля 2016

вы можете использовать разделяемую память для двух процессов, чтобы обмениваться данными, отметив MemoryMappedFile

вы в основном создадите файл отображения памяти mmf в родительском процессе, используяс помощью оператора using создайте второй процесс до его завершения и позвольте ему записать результат в mmf, используя BinaryWriter, затем прочитав результат из mmf, используя родительский процесс, вы также можете передать mmfимя, используя аргументы командной строки или его жесткий код.

при использовании сопоставленного файла в родительском процессе убедитесь, что дочерний процесс записывает результат в сопоставленный файл, прежде чем сопоставленный файл будет выпущен в родительском процессе.

Пример: родительский процесс

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

Дочерний процесс

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

, чтобы использовать этот пример, вам необходимо создать решение с двумя проектами внутри, а затем вывзять результат сборки дочернего процесса из% childDir% / bin / debug и скопировать его в% parentDirectory% / bin / debug, затем запустить родительский проект

childDir и parentDirectory являются имена папок ваших проектов на ПК удачи:)

4 голосов
/ 27 ноября 2010
  1. Можно получить выходные данные оболочки командной строки процесса, как описано здесь: http://www.c -sharpcorner.com / UploadFile / edwinlima / SystemDiagnosticProcess12052005035444AM / SystemDiagnosticProcess.aspx

  2. Это зависит от mencoder. Если он выводит этот статус в командной строке, тогда yes:)

1 голос
/ 23 июля 2018

Как запустить процесс (такой как bat-файл, скрипт на Perl, консольная программа) и отобразить его стандартный вывод в форме 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();    

По этой ссылке вы можете найти ProcessCaller: Запуск процесса и отображение его стандартного вывода

0 голосов
/ 11 января 2019

Вы можете зарегистрировать вывод процесса, используя следующий код:

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