2009-11-24 14 views
5

コンソールアプリケーションのstdinとstdoutをリダイレクトしようとしているので、F#経由で対話できます。しかし、コンソールアプリケーションによっては、明白なコードが失敗するようです。以下のF#コードがdirのために動作しますがpythonfsiために(ハング)失敗:標準入力と標準出力を.Netでリダイレクトする

open System 
open System.Diagnostics 

let f = new Process() 
f.StartInfo.FileName <- "python" 
f.StartInfo.UseShellExecute <- false 
f.StartInfo.RedirectStandardError <- true 
f.StartInfo.RedirectStandardInput <- true 
f.StartInfo.RedirectStandardOutput <- true 
f.EnableRaisingEvents <- true 
f.StartInfo.CreateNoWindow <- true 
f.Start() 
let line = f.StandardOutput.ReadLine() 

これは、Pythonでハングが、dirのために動作します。

これはpythonやfsiとreadlineを使っているのですか、それとも私は間違いがありますか?私はfsiやPython REPLとF#のやり取りをすることができますか?

答えて

3

これはあなたが探しているコードです(これは第9章のスクリプトで書いたとおりです)。前述のように、ReadLineはあらゆる種類のハングにつながる完全な行がなくなるまでブロックします。最善の策は、OutputDataRecievedイベントにフックすることです。 (アップprettiedされるように立てることができる)

open System.Text 
open System.Diagnostics 

let shellEx program args = 

    let startInfo = new ProcessStartInfo() 
    startInfo.FileName <- program 
    startInfo.Arguments <- args 
    startInfo.UseShellExecute <- false 

    startInfo.RedirectStandardOutput <- true 
    startInfo.RedirectStandardInput <- true 

    let proc = new Process() 
    proc.EnableRaisingEvents <- true 

    let driverOutput = new StringBuilder() 
    proc.OutputDataReceived.AddHandler(
     DataReceivedEventHandler(
      (fun sender args -> driverOutput.Append(args.Data) |> ignore) 
     ) 
    ) 

    proc.StartInfo <- startInfo 
    proc.Start() |> ignore 
    proc.BeginOutputReadLine() 

    // Now we can write to the program 
    proc.StandardInput.WriteLine("let x = 1;;") 
    proc.StandardInput.WriteLine("x + x + x;;") 
    proc.StandardInput.WriteLine("#q;;") 

    proc.WaitForExit() 
    (proc.ExitCode, driverOutput.ToString()) 

出力:

val it : int * string = 
    (0, 
    "Microsoft F# Interactive, (c) Microsoft Corporation, All Rights ReservedF# Version 1.9.7.8, compiling for .NET Framework Version v2.0.50727For help type #help;;> val x : int = 1> val it : int = 3> ") 
+0

これは、私はまだ、各コマンドの出力が開始され、終了する場所を見つける方法を把握しようと周りいじるい除き、完璧です。 Splitting on>はあまり強くないようです。私は "--fsi-server:test"を引数として渡してみましたが、 "SERVER-PROMPT>"が得られていないようです。何か案は? – Tristan

+0

残念なことに、FSIでは、コマンドが '>'が表示されるのを待つ以外の実行が行われたかどうかを知ることはできません。明らかに堅牢ではありません。 自動化では、次のヒューリスティックを使用します。「\ r \ n>」&&を待ち、2回以上新しい出力が書き込まれません。 –

+0

ありがとうございます。 fsiserver.fsはIPCで動作するようですが、VSシェルのように使用する方法は明白ではありません。 – Tristan

2

私は実際にはであり、読むべきテキストの行をにしています。 ReadLineの呼び出しは、キャリッジリターンまたはラインフィードで終わる実線が使用可能になるまでブロックされます。

文字を一度に読み取ってみてください(ReadLineの代わりにRead)。何が起こるかを確認してください。

2

おそらくマイケル・ペトロッタが言っていることでしょう。そうであれば、文字を読んでも助けにならないでしょう。あなたがする必要があるのは、あなたのアプリケーションがブロックされないように非同期バージョン(BeginOutputReadLine)を使用することです。

関連する問題