start - visual studio 2017 c#



如何在.NET中產生一個進程並捕獲它的STDOUT? (6)

這個問題在這裡已經有了答案:

我需要產生一個作為控制台應用程序的子進程,並捕獲它的輸出。

我寫了一個方法的以下代碼:

string retMessage = String.Empty;
ProcessStartInfo startInfo = new ProcessStartInfo();
Process p = new Process();

startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;

startInfo.UseShellExecute = false;
startInfo.Arguments = command;
startInfo.FileName = exec;

p.StartInfo = startInfo;
p.Start();

p.OutputDataReceived += new DataReceivedEventHandler
(
    delegate(object sender, DataReceivedEventArgs e)
    {
        using (StreamReader output = p.StandardOutput)
        {
            retMessage = output.ReadToEnd();
        }
    }
);

p.WaitForExit();

return retMessage;

但是,這不會返回任何內容。 我不相信OutputDataReceived事件被回調,或WaitForExit()命令可能會阻塞線程,因此它永遠不會回調。

有什麼建議?

編輯:看起來我正在努力與回調。 這樣做:

return p.StandardOutput.ReadToEnd(); 

看起來工作正常。


Answer #1

以下是我用來運行進程並獲取其輸出和錯誤的方法:

public static string ShellExecute(this string path, string command, TextWriter writer, params string[] arguments)
    {
        using (var process = Process.Start(new ProcessStartInfo { WorkingDirectory = path, FileName = command, Arguments = string.Join(" ", arguments), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true }))
        {
            using (process.StandardOutput)
            {
                writer.WriteLine(process.StandardOutput.ReadToEnd());
            }
            using (process.StandardError)
            {
                writer.WriteLine(process.StandardError.ReadToEnd());
            }
        }

        return path;
    }

例如 :

@"E:\Temp\MyWorkingDirectory".ShellExecute(@"C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\svcutil.exe", Console.Out);

Answer #2

您需要在設置StartInfo後調用p.Start()來實際運行該進程。 事實上,你的函數可能掛在WaitForExit()調用上,因為這個過程從未真正開始過。


Answer #3

我需要捕獲stdout和stderr,並且如果進程沒有按預期的方式退出,就讓它超時。 我想出了這個:

Process process = new Process();
StringBuilder outputStringBuilder = new StringBuilder();

try
{
process.StartInfo.FileName = exeFileName;
process.StartInfo.WorkingDirectory = args.ExeDirectory;
process.StartInfo.Arguments = args;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.EnableRaisingEvents = false;
process.OutputDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data);
process.ErrorDataReceived += (sender, eventArgs) => outputStringBuilder.AppendLine(eventArgs.Data);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
var processExited = process.WaitForExit(PROCESS_TIMEOUT);

if (processExited == false) // we timed out...
{
    process.Kill();
    throw new Exception("ERROR: Process took too long to finish");
}
else if (process.ExitCode != 0)
{
    var output = outputStringBuilder.ToString();
    var prefixMessage = "";

    throw new Exception("Process exited with non-zero exit code of: " + process.ExitCode + Environment.NewLine + 
    "Output from process: " + outputStringBuilder.ToString());
}
}
finally
{                
process.Close();
}

我將stdout和stderr管道輸入到同一個字符串中,但如果需要,可以將它分開。 它使用事件,所以它應該處理它們,因為它們來了(我相信)。 我已經成功運行了,並且很快就會進行批量測試。


Answer #4

由於應用程序在第一次BeginOutputReadLine();之後退出,Judah的回答對我來說不起作用(或者不完整BeginOutputReadLine();

這對我來說是一個完整的片段,讀取ping的常量輸出:

        var process = new Process();
        process.StartInfo.FileName = "ping";
        process.StartInfo.Arguments = "google.com -t";
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.UseShellExecute = false;
        process.OutputDataReceived += (sender, a) => Console.WriteLine(a.Data);
        process.Start();
        process.BeginOutputReadLine();
        process.WaitForExit();

Answer #5

這是我驗證過的代碼。 我使用它來產生MSBuild並監聽它的輸出:

process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += (sender, args) => Console.WriteLine("received output: {0}", args.Data);
process.Start();
process.BeginOutputReadLine();

Answer #6

這裡有一些完整而簡單的代碼來完成這個任務。 當我使用它時,這工作得很好。

var processStartInfo = new ProcessStartInfo
{
    FileName = @"C:\SomeProgram",
    Arguments = "Arguments",
    RedirectStandardOutput = true,
    UseShellExecute = false
};
var process = Process.Start(processStartInfo);
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

請注意,這只能捕獲標準輸出 ; 它不會捕獲標準錯誤 。 如果你想同時使用這種技術 ,每個流。





spawning