web-dev-qa-db-ja.com

Process.start:出力を取得する方法?

Mono/.NETアプリから外部のコマンドラインプログラムを実行したいのですが。たとえば、mencoderを実行します。出来ますか:

  1. シェルのコマンドライン出力を取得して、テキストボックスに書き込むには
  2. 経過時間とともにプログレスバーを表示する数値を取得するには?
261
stighy

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()を使用できます。読んだ文字列に無効な数字が含まれている場合は、まず文字列を操作する必要があります。

397
Ferruccio

出力を同期的または非同期的に処理できます。

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);
209
T30

エラーと出力の両方を読みたいが、他の回答で提供されている解決策(私のような)でデッドロックに陥っている人のために、StandardOutputプロパティに関するMSDNの説明を読んだ後に構築した解決策です。

答えは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

これを行うための標準的な.NETの方法は、Process ' StandardOutput ストリームから読み取ることです。リンクされたMSDNドキュメントに例があります。同様に、 StandardError から読み取り、 StandardInput に書き込むことができます。

7
driis

2つのプロセス間で共有メモリを使用して通信できます。チェックアウト MemoryMappedFile

"using"ステートメントを使用して、親プロセスで主にメモリマップファイルmmfを作成し、次に終了するまで2番目のプロセスを作成し、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();
    }

このサンプルを使用するには、内部に2つのプロジェクトを含むソリューションを作成する必要があります。次に、%childDir%/ bin/debugから子プロセスのビルド結果を取得し、それを%parentDirectory%/ bin/debugにコピーして実行します。親プロジェクト

childDirparentDirectoryは、PC上のプロジェクトのフォルダ名です。

4
shakram02
  1. ここで説明されているようにプロセスのコマンドラインシェル出力を取得することは可能です: http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx

  2. これはmencoderに依存します。それがコマンドラインでこのステータスを出力するならば、はい:)

3
basarat

プロセス(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はこのリンクにあります。 プロセスを起動してその標準出力を表示します

1

以下のコードを使用してプロセス出力を記録できます。

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