2010-06-17 11 views
10

आउटपुट "स्ट्रीमिंग" मैं एफ # से एक प्रक्रिया शुरू करने की कोशिश कर रहा हूं, इसे समाप्त होने तक प्रतीक्षा करें, लेकिन इसके आउटपुट को क्रमशः पढ़ें।एक प्रक्रिया को सिंक्रनाइज़ेशन से शुरू करना, और आउटपुट

क्या यह करने का यह सही/सबसे अच्छा तरीका है? (मेरे मामले में मैं 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 

क्या मुझे समझ नहीं आता कैसे proc.Start() एक बूलियन लौट सकते हैं और यह भी कर सकते हैं प्रगतिशील रूप से आउटपुट प्राप्त करने के लिए मेरे लिए पर्याप्त असीमित हो।

दुर्भाग्य से, मैं वर्तमान में एक बड़ा पर्याप्त भंडार नहीं है - या पर्याप्त मशीन धीमी हो, बताने के लिए क्या आदेश बातों में हो रही हैं सक्षम होने के लिए ...

अद्यतन

मैंने कोशिश ब्रायन की सुझाव, और यह काम करता है।

मेरा प्रश्न थोड़ा अस्पष्ट था। मेरी गलतफहमी यह थी कि मैंने माना कि प्रक्रिया। स्टार्ट() ने पूरी तरह से प्रक्रिया की सफलता पूरी की, न केवल 'स्टार्ट' की, और इस प्रकार मैं नहीं देख सका कि यह काम कैसे कर सकता है।

+1

मुझे इस तरह के कार्य के लिए असिंक्रोनस वर्कफ़्लो का उपयोग करके कुछ सफलता मिली: http://stackoverflow.com/questions/2649161/need-help-regarding-async-and-fsi – Stringer

+0

मुझे वास्तव में यह सुनिश्चित नहीं है कि सवाल क्या है यहाँ। क्या आपका कोड काम से ऊपर है या नहीं? समस्या क्या है? –

+1

ऐसा लगता है कि आप tester.exe लिख सकते हैं, जो स्टडआउट और फ्लश करने के लिए कुछ पंक्तियां लिखता है, दो सेकंड प्रतीक्षा करता है, और दो पंक्तियां लिखता है ... और इसका उपयोग यह जांचने के लिए करें कि यह कोड आपके जैसा व्यवहार करता है या नहीं? – Brian

उत्तर

12

आपके द्वारा लिखे गए फॉर्म में लिखा गया कोड (लगभग) ठीक है: प्रक्रिया। अपनी प्रक्रिया को शुरू करने की प्रक्रिया शुरू करें, ठीक है, एक और प्रक्रिया है, इसलिए आपकी आउटपुट स्ट्रीम पढ़ती है जो आपकी प्रक्रिया निष्पादन के समानांतर में होती है। हालांकि एक मुद्दा यह है कि आपको प्रक्रिया में कॉल करने के लिए फेंकना चाहिए। अंत में प्रतीक्षा करें - तथ्य यह है कि आउटपुट स्ट्रीम बंद है, यह इस बात को इंगित नहीं करता है कि प्रक्रिया समाप्त हो गई है।

हालांकि यदि आप प्रक्रिया के दोनों stdout और stderr को पढ़ने की कोशिश करते हैं तो आप सिंक्रोनियस पढ़ने के साथ समस्याओं में भाग लेंगे: 2 धाराओं को एक साथ सिंक्रनाइज़ करने और एक साथ पढ़ने का कोई तरीका नहीं है - यदि आप stdout पढ़ते हैं और प्रक्रिया लिख ​​रही है तो आप डेडलॉक करेंगे stderr और इसके उत्पादन या इसके विपरीत उपभोग करने के लिए इंतजार कर रहा है।

इस मध्यस्थता के लिए, आपको, OutputDataRecieved और ErrorDataRecieved की सदस्यता ले सकते इस तरह:

async { 
    while true do 
     let! args = Async.AwaitEvent p.OutputDataReceived 
     ... 
} |> Async.StartImmediate 

एफ # के लिए शैली प्रतिक्रियाशील घटना से निपटने:

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() } 

तुम भी की तर्ज पर कुछ लिख सकते हैं ।

+0

+1 जो मैंने नहीं पूछा था, उसके जवाब देने के लिए +1 :) आपके कोड में बस एक त्रुटि यह है कि प्रक्रिया। स्टार्ट() प्रक्रिया को वापस नहीं करता है, यह एक बूलियन देता है। – Benjol

+2

मैं एक स्थिर प्रक्रिया को कॉल कर रहा हूं। स्टार्ट (ProcessStartInfo) जो एक प्रक्रिया (http://msdn.microsoft.com/en-us/library/0w4h05yb.aspx) देता है –

+1

इस समाधान के साथ समस्या यह है कि ईवेंट 'आउटपुटडेटा प्राप्त' और 'त्रुटि डेटाटाइसेव' केवल ईओएल भेजे जाने के बाद ही आग लगती है, इसलिए यह हो सकता है कि प्रक्रिया उपयोगकर्ता को उसी पंक्ति में उत्तर देने के लिए कुछ कहती है (उदाहरण के लिएक्या आप निश्चित हैं? [वाई/एन] ') और फिर यह एफ # प्रक्रिया रैपर द्वारा मुद्रित नहीं किया जाएगा – knocte

संबंधित मुद्दे