Process.start: çıktı nasıl alınır?


306

Mono / .NET uygulamamdan harici bir komut satırı programı çalıştırmak istiyorum. Örneğin, mencoder çalıştırmak istiyorum . Mümkün mü:

  1. Komut satırı kabuk çıktısını almak ve metin kutuma yazmak için?
  2. Sayısal değerin, geçen süreyi gösteren bir ilerleme çubuğu göstermesini sağlamak için?

Yanıtlar:


458

Ne zaman oluşturmak Processnesne kümesi StartInfouygun:

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

sonra işlemi başlatın ve okuyun:

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

Sen kullanabilirsiniz int.Parse()veya int.TryParse()sayısal değerlere dizeleri dönüştürmek. Okuduğunuz dizelerde geçersiz sayısal karakterler varsa, önce bazı dize işlemleri yapmanız gerekebilir.


4
StandardError ile nasıl başa çıkabileceğinizi merak ediyordum. BTW Bu kod snippet'ini gerçekten seviyorum! güzel ve temiz.
codea

3
Teşekkürler, Ama net olmadığını düşünüyorum: Bunu yapmak için başka bir döngü eklemeli miyim?
codea

@codea - Anlıyorum. Her iki akış da EOF'a ulaştığında sona eren bir döngü oluşturabilirsiniz. Bu biraz karmaşık olabilir, çünkü bir akış ilk önce kaçınılmaz olarak EOF'a çarpacaktır ve bundan sonra okumak istemezsiniz. İki farklı iş parçacığında iki döngü de kullanabilirsiniz.
Ferruccio

1
akışın bitmesini beklemek yerine sürecin kendisi sona erene kadar okumak daha mı sağlam?
Gusdor

@Gusdor - Sanmıyorum. İşlem sona erdiğinde akışları otomatik olarak kapatılacaktır. Ayrıca, bir süreç, sona ermeden çok önce akışlarını kapatabilir.
Ferruccio

254

Çıktınızı işleyebilirsiniz eşzamanlı veya eşzamansız .

1. Senkron örnek

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

Her ikisini de işlemenin daha iyi olduğunu unutmayın çıkışı ve hataları : bunlar ayrı ayrı ele alınması gerekir.

(*) Bazı komutlar için (burada StartInfo.Arguments)/c yönergeyi , aksi takdirde işlem WaitForExit().

2. Eşzamansız örnek

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

Çıktı ile karmaşık işlemler yapmanız gerekmiyorsa, yalnızca işleyicileri doğrudan satır içine ekleyerek OutputHandler yöntemini atlayabilirsiniz:

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

2
zaman uyumsuz seviyorum! Bu kodu VB.net'te (biraz transkripsiyonla) kullanabildim
Richard Barker

note 'string output = process.StandardOutput.ReadToEnd ();' çok sayıda çıktı satırı varsa büyük bir dize üretebilir; zaman uyumsuz örnek ve Ferruccio'nun yanıtı çıktıyı satır satır işler.
Andrew Hill

5
Not: ilk (senkron) yaklaşımınız doğru değil! StandardOutput ve StandardError değerlerini eşzamanlı olarak okumamalısınız! çıkmaz kilitlere neden olur. en azından bunlardan biri zaman uyumsuz olmalıdır.
S.Serpooshan

6
Process.WaitForExit (), iş parçacığı engellemesidir, bu nedenle eşzamanlıdır. Cevabın konusu değil, ama bunu ekleyebileceğimi düşündüm. Process.EnableRaisingEvents = true öğesini ekleyin ve Exited olayını tamamen eşzamansız olmak için kullanın.
Tom

Doğrudan yönlendirmek mümkün değil mi? Sass çıktısının tüm renklenmesini kullanıyorum?
Ini

14

Tamam, hem Hataların hem de Çıktıların okunmasını isteyen, ancak diğer yanıtlarda (benim gibi) sağlanan çözümlerden herhangi biriyle kilitlenme elde eden herkes için, StandardOutputözellik için MSDN açıklamasını okuduktan sonra oluşturduğum bir çözüm .

Cevap T30'un koduna dayanmaktadır:

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(ErrorOutputHandler);
    //* 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 ErrorOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) 
{
    //* Do your stuff with the output (write to console/log/StringBuilder)
    Console.WriteLine(outLine.Data);
}

Bunu eklediğiniz için teşekkürler. Hangi komutu kullandığınızı sorabilir miyim?
T30

Bir mysqldump.exe başlatmak, kullanıcıya uygulamanın her iletiyi göstermek, bitirmek için beklemek ve daha sonra bazı görevleri gerçekleştirmek için tasarlanmış c # bir uygulama geliştiriyorum. Ne tür bir komuttan bahsettiğinizi anlayamıyorum? Tüm bu soru c # 'dan bir işlem başlatmakla ilgilidir.
cubrman

1
iki ayrı işleyici kullanırsanız kilitlenmezsiniz
Ovi

siz de örnekte, süreci okudunuz.StandardOutput sadece bir kez başlattıktan sonra ... ama işlem devam ederken biri sürekli olarak okumak ister, değil mi?
Ovi



4

iletişim kurmak, kontrol etmek için 2 işlem için paylaşılan belleği kullanabilirsiniz MemoryMappedFile

esas mmfolarak üst işlemde "using" deyimini kullanarak bir bellek eşlemeli dosya oluşturacak, sonra sona erene kadar ikinci işlemi oluşturacak ve sonucu mmfkullanarak yazmasına izin verecek BinaryWriter, ardından mmfüst işlemi kullanarak sonucu okuyacaksınız, ayrıca Geçmmf komut satırı argümanları veya sabit kod kullandığını isim.

Eşlenen dosyayı üst işlemde kullanırken, eşlenen dosya üst işlemde serbest bırakılmadan önce alt işlemi eşlenen dosyaya yazdığınız sonucu aldığınızdan emin olun

Örnek: üst süreç

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

Çocuk süreci

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

Bu örneği kullanmak için, içinde 2 proje bulunan bir çözüm oluşturmanız gerekir, ardından% childDir% / bin / debug öğesinden alt sürecin derleme sonucunu alıp% parentDirectory% / bin / debug öğesine kopyalayıp ardından ana proje

childDirve parentDirectorypc iyi şanslar projelerinizin klasör isimleri :)


1

Bir işlem nasıl başlatılır (bir bat dosyası, perl betiği, konsol programı) ve standart çıktısının bir Windows formunda görüntülenmesi:

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

ProcessCallerBu bağlantıda bulabilirsiniz : Bir işlemi başlatma ve standart çıktısını görüntüleme


1

Aşağıdaki kodu kullanarak işlem çıktısını günlüğe kaydedebilirsiniz:

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

1

Win ve linux'da benim için çalışan çözüm şu

// 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 };
            }
        }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.