Ben*_*jol 11 .net f# processstartinfo synchronous
我正在尝试从F#开始一个进程,等到它完成,但还要逐步读取它的输出.
这是正确/最好的方式吗?(在我的情况下,我正在尝试执行git命令,但这与问题相关)
let gitexecute (logger:string->unit) cmd = 
    let procStartInfo = new ProcessStartInfo(@"C:\Program Files\Git\bin\git.exe", cmd) 
    // Redirect to the Process.StandardOutput StreamReader.
    procStartInfo.RedirectStandardOutput <- true
    procStartInfo.UseShellExecute <- false;
    // Do not create the black window.
    procStartInfo.CreateNoWindow <- true;
    // Create a process, assign its ProcessStartInfo and start it
    let proc = new Process();
    proc.StartInfo <- procStartInfo;
    proc.Start() |> ignore
    // Get the output into a string
    while not proc.StandardOutput.EndOfStream do
        proc.StandardOutput.ReadLine() |> logger
Run Code Online (Sandbox Code Playgroud)
我不明白的是proc.Start()如何返回一个布尔值,也足够异步,让我逐步获得输出.
不幸的是,我目前没有足够大的存储库 - 或者足够慢的机器,以便能够分辨出事情的顺序......
UPDATE
我试过Brian的建议,它确实有效.
我的问题有点模糊.我的误解是,我假设的Process.Start()返回进程的成功作为一个整体,而不是仅仅的"开始",因此我看不出它如何能工作.
Dmi*_*mov 14
您在编写它的表单中编写的代码(几乎)是正确的:process.Start启动您指定的进程,以及另一个进程,因此您的输出流读取将与您的流程执行并行执行.但有一个问题是你最后应该调用process.WaitForExit - 输出流关闭的事实并不意味着进程终止.
但是,如果您尝试读取进程的stdout和stderr,则会遇到同步读取问题:无法同步并同时读取2个流 - 如果读取stdout并且进程正在写入stderr并等待你要消耗它的输出,反之亦然.
要调解它,您可以订阅OutputDataRecieved和ErrorDataRecieved,如下所示:
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() }
Run Code Online (Sandbox Code Playgroud)
您还可以写下以下内容:
async {
    while true do
        let! args = Async.AwaitEvent p.OutputDataReceived
        ...
} |> Async.StartImmediate
Run Code Online (Sandbox Code Playgroud)
用于F#式反应事件处理.
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           2116 次  |  
        
|   最近记录:  |