私は、出力にstdout
出力とstderr
出力の両方を含む別のプログラムを呼び出すプログラムを書こうとします。例えばProcessクラスからのイベントを間違った順序で受け取らないようにするにはどうすればよいですか?
、私は呼んで、このプログラムは、エラーを含むF#ファイルをコンパイルしようとしているF#コンパイラのようになります。
F# Compiler for F# 4.0 (Open Source Edition)
Freely distributed under the Apache 2.0 Open Source License
/builds/someLib.fs(27,42): error FS0001: Type mismatch. Expecting a
string * string
but given a
string * string * 'a
The tuples have differing lengths of 2 and 3
(最初の2行はstderr
にstdout
、残りの部分に印刷されている。)
だから私は、プロセスのクラスでこの方法を扱うプログラムを書く:
type OutChunk = StdOut of string | StdErr of string
type OutputBuffer = list<OutChunk>
type ProcessResult = { ExitCode: int; Output: OutputBuffer }
module Process =
let Execute (command: string, args: string, hidden: bool)
: ProcessResult =
// I know, this shit below is mutable, but it's a consequence of dealing with .NET's Process class' events
let outputBuffer = new System.Collections.Generic.List<OutChunk>()
let outputBufferLock = new Object()
use outWaitHandle = new AutoResetEvent(false)
use errWaitHandle = new AutoResetEvent(false)
let startInfo = new ProcessStartInfo(command, args)
startInfo.UseShellExecute <- false
startInfo.RedirectStandardOutput <- true
startInfo.RedirectStandardError <- true
use proc = new System.Diagnostics.Process()
proc.StartInfo <- startInfo
let outReceived (e: DataReceivedEventArgs): unit =
if (e.Data = null) then
outWaitHandle.Set() |> ignore
else
if not (hidden) then
Console.WriteLine(e.Data)
lock outputBufferLock (fun _ -> outputBuffer.Add(OutChunk.StdOut(e.Data)))
let errReceived (e: DataReceivedEventArgs): unit =
if (e.Data = null) then
errWaitHandle.Set() |> ignore
else
if not (hidden) then
Console.Error.WriteLine(e.Data)
lock outputBufferLock (fun _ -> outputBuffer.Add(OutChunk.StdErr(e.Data)))
proc.OutputDataReceived.Add outReceived
proc.ErrorDataReceived.Add errReceived
proc.Start() |> ignore
let exitCode =
try
proc.BeginOutputReadLine()
proc.BeginErrorReadLine()
proc.WaitForExit()
proc.ExitCode
finally
outWaitHandle.WaitOne() |> ignore
errWaitHandle.WaitOne() |> ignore
{ ExitCode = exitCode; Output = List.ofSeq(outputBuffer) }
let rec PrintToScreen (outputBuffer: OutputBuffer) =
match outputBuffer with
| [] ->()
| head::tail ->
match head with
| StdOut(out) -> Console.WriteLine(out)
| StdErr(err) -> Console.Error.WriteLine(err)
PrintToScreen(tail)
しかし、私はCでロックを使用しても、変更可能なリストへの書き込み時に競合状態を防ぐために、上記の頌歌、私はF#コンパイラを呼び出し、F#のプログラムを実行し、私はPrintToScreen
関数を呼び出すとき時々、私はストリームが混在取得:
F# Compiler for F# 4.0 (Open Source Edition)
/builds/someLib.fs(27,42): error FS0001: Type mismatch. Expecting a
Freely distributed under the Apache 2.0 Open Source License
string * string
but given a
string * string * 'a
The tuples have differing lengths of 2 and 3
(あなたのようコンパイルエラーの前にライセンステキストが到着しているはずですが、それはありませんでした)
どうすれば可能ですか?どのように正しいの順序でストリーム/イベントを受信する対角化System.Diagnostics.Process
クラスを扱うには?
問題はおそらくバッファリングの違いにあります。同じようにバッファにstdoutとstderrを見てください –
彼らはすでに(私が理解する限り)同じ方法でバッファリングしていますので、あなたは何を提案しているのですか? – knocte
通常、出力がバッファされている間、エラーはバッファされません。これをどこかで変更するオプションがあります。 –