I\'m looking at trying to start a process from F#, wait till it\'s finished, but also read it\'s output progressively.
Is this the right/best way to do it? (In m
The code you wrote in the form you wrote it is (almost) ok: process.Start start the process you specify in, well, another process, so your output stream reads will happen in parallel with your process execution. One issue though is that you should throw in a call to process.WaitForExit in the end - the fact that output stream is closed does not imply that process terminated.
However you will run into problems with synchronyous reading if you try to read both stdout and stderr of the process: there is no way of reading 2 streams synchronously and simultaneously - you will deadlock if you read stdout and process is writing to stderr and waits for you to consume its output or vice versa.
To mediate this, you can subscribe to OutputDataRecieved and ErrorDataRecieved, like this:
type ProcessResult = { exitCode : int; stdout : string; stderr : string }
let executeProcess (exe,cmdline) =
let psi = new System.Diagnostics.ProcessStartInfo(exe,cmdline)
psi.UseShellExecute <- false
psi.RedirectStandardOutput <- true
psi.RedirectStandardError <- true
psi.CreateNoWindow <- true
let p = System.Diagnostics.Process.Start(psi)
let output = new System.Text.StringBuilder()
let error = new System.Text.StringBuilder()
p.OutputDataReceived.Add(fun args -> output.Append(args.Data) |> ignore)
p.ErrorDataReceived.Add(fun args -> error.Append(args.Data) |> ignore)
p.BeginErrorReadLine()
p.BeginOutputReadLine()
p.WaitForExit()
{ exitCode = p.ExitCode; stdout = output.ToString(); stderr = error.ToString() }
You can also write something along the lines of:
async {
while true do
let! args = Async.AwaitEvent p.OutputDataReceived
...
} |> Async.StartImmediate
for F#-style reactive event handling.