2012-01-10 24 views
17

से लाइव आउटपुट प्राप्त करें मुझे अपनी परियोजना में कोई समस्या है। मैं एक प्रक्रिया, 7z.exe (कंसोल संस्करण) लॉन्च करना चाहता हूं। मैं कोशिश की है तीन अलग अलग बातें:प्रक्रिया

  • Process.StandardOutput.ReadToEnd();
  • BeginOutputReadLine
  • StreamWriter

कुछ भी नहीं काम करता है OutputDataReceived &। प्रक्रिया के अंत के लिए यह हमेशा "प्रतीक्षा करें" जो मैं चाहता हूं उसे दिखाने के लिए। मेरे पास कोई कोड नहीं है, बस अगर आप मेरे कोड को सूचीबद्ध चीजों में से एक के साथ चाहते हैं। धन्यवाद।

संपादित करें: मेरे कोड:

 process.StartInfo.UseShellExecute = false; 
     process.StartInfo.RedirectStandardOutput = true; 
     process.StartInfo.CreateNoWindow = true; 
     process.Start(); 

     this.sr = process.StandardOutput; 
     while (!sr.EndOfStream) 
     { 
      String s = sr.ReadLine(); 
      if (s != "") 
      { 
       System.Console.WriteLine(DateTime.Now + " - " + s); 
      } 
     } 

या

process.StartInfo.UseShellExecute = false; 
process.StartInfo.RedirectStandardOutput = true; 
process.OutputDataReceived += new DataReceivedEventHandler(recieve); 
process.StartInfo.CreateNoWindow = true; 
process.Start(); 
process.BeginOutputReadLine(); 
process.WaitForExit(); 
public void recieve(object e, DataReceivedEventArgs outLine) 
{ 
    System.Console.WriteLine(DateTime.Now + " - " + outLine.Data); 
} 

या

process.StartInfo.UseShellExecute = false; 
process.StartInfo.RedirectStandardOutput = true; 
process.Start(); 
string output = p.StandardOutput.ReadToEnd(); 
process.WaitForExit(); 

कहाँ "प्रक्रिया" मेरे पूर्व निर्मित प्रक्रिया

ठीक है मुझे पता है क्यों यह ठीक से काम नहीं करता है: 7z.exe बग है: यह कंसोल में प्रतिशत लोडिंग प्रदर्शित करता है, और यह केवल तभी जानकारी भेजता है जब वर्तमान फ़ाइल समाप्त हो जाती है। उदाहरण के लिए निष्कर्षण में, यह ठीक काम करता है :)। मैं 7z.exe के बिना 7z फ़ंक्शंस का उपयोग करने के लिए एक और तरीका खोजूंगा (शायद 7za.exe या कुछ DLL के साथ)। सभी को धन्यवाद। प्रश्न का उत्तर देने के लिए, OuputDataRecieved ईवेंट ठीक काम करता है!

+0

किसी भी कारण से आप 7zip से DLL/SDK downloadabe का उपयोग नहीं करते हैं जो किसी भी कंसोल-आधारित तकनीक की तुलना में अधिक नियंत्रण के लिए अनुमति देता है? – Yahia

+0

यह उस प्रक्रिया को देखने में मदद करेगा जिसे आपने प्रक्रिया के साथ कोशिश की है उदाहरण के लिए, जहां आप प्रक्रिया – MethodMan

+0

बना रहे हैं क्योंकि 7z.exe सभी कार्यों को शामिल करता है। – Extaze

उत्तर

16

इस पेज पर एक नजर डालें उपयोग कर सकते हैं, ऐसा लगता है कि यह आपके लिए समाधान है : http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspx और http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx

[संपादित करें] यह एक काम कर उदाहरण:

 Process p = new Process(); 
     p.StartInfo.RedirectStandardError = true; 
     p.StartInfo.RedirectStandardOutput = true; 
     p.StartInfo.UseShellExecute = false; 
     p.StartInfo.CreateNoWindow = true; 
     p.StartInfo.FileName = @"C:\Program Files (x86)\gnuwin32\bin\ls.exe"; 
     p.StartInfo.Arguments = "-R C:\\"; 

     p.OutputDataReceived += new DataReceivedEventHandler(
      (s, e) => 
      { 
       Console.WriteLine(e.Data); 
      } 
     ); 
     p.ErrorDataReceived += new DataReceivedEventHandler((s, e) => { Console.WriteLine(e.Data); }); 

     p.Start(); 
     p.BeginOutputReadLine(); 

बीटीडब्ल्यू, एलएस-आर सी: \ सी की जड़ से सभी फाइलों को सूचीबद्ध करता है: रिकर्सिवली। ये बहुत सारी फाइलें हैं, और मुझे यकीन है कि यह तब नहीं किया जाता जब स्क्रीन में पहले परिणाम दिखाई देते हैं। एक संभावना है कि 7zip इसे दिखाने से पहले आउटपुट रखती है। मुझे यकीन नहीं है कि आप प्रोसेस को कौन से पैरा देते हैं।

+0

प्राप्त करने के लिए है मेरा कोड देखें:/ – Extaze

+0

मुझे लगता है कि, आपको इसका उपयोग करना चाहिए घटना आउटपुटडेटा प्राप्त हुई, इस समय मेरे पास परीक्षण करने का समय नहीं है, शायद बाद में। (http://harbertc.wordpress.com/2006/05/16/reading-text-from-a-process-executed-programmatically-in-c/) –

+0

मैंने सब कुछ करने की कोशिश की, लेकिन समस्या 7z.exe थी। मैंने C# (SevenZipSharp) के लिए 7z लाइब्रेरी लेने का निर्णय लिया है और समस्या हल हो गई थी। धन्यवाद;) – Extaze

0

इसे आजमाएं।

 Process notePad = new Process(); 

     notePad.StartInfo.FileName = "7z.exe"; 
     notePad.StartInfo.RedirectStandardOutput = true; 
     notePad.StartInfo.UseShellExecute = false; 

     notePad.Start(); 
     StreamReader s = notePad.StandardOutput; 



     String output= s.ReadToEnd(); 


     notePad.WaitForExit(); 

उपरोक्त को thread में रहने दें।

अब यूआई के लिए उत्पादन को अद्यतन करने के लिए, आप एक timer दो के साथ लाइनों

Console.Clear(); 
    Console.WriteLine(output); 

यह मदद मिल सकती है आप

+1

जैसा कि मैं देख सकता हूं, यह कोड तब तक इंतजार करेगा जब तक यह पूरा नहीं हो जाता है। जैसा कि सवाल में बताया गया है, वह तब तक इंतजार नहीं करना चाहता जब तक कि यह पूरा नहीं हो जाता है, लेकिन लाइव आउटपुट –

+0

चाहता है जैसा कि माइकल ने कहा था, "अंतिम" आउटपुट – Extaze

1

मैंने सीएमडीप्रोसेसर क्लास का उपयोग कई परियोजनाओं पर here का वर्णन किया है। यह पहली बार थोड़ा मुश्किल लग रहा है लेकिन उपयोग करने में बहुत आसान है।

+0

का परीक्षण करते समय 7z.exe के लिए पूरी तरह से काम करता है काम नहीं करता है ... यह प्रक्रिया के लिए इंतजार करता है मुझे सूचनाओं को दिखाने के लिए बंद हो जाता है ... – Extaze

4

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

समस्या यह है कि, जब आप इस तरह एक निष्पादन योग्य लॉन्च करते हैं तो यह आपके दूसरे ऐप को अवरुद्ध करने वाले दूसरे थ्रेड में आग लगने जा रहा है, जिससे लटका हुआ है। यदि आप इस समय के दौरान अपने उपयोगकर्ताओं को उपयोगी प्रतिक्रिया प्रदान करना चाहते हैं तो कताई आइकन से परे आपके संबंधित ओएस द्वारा स्वीकार किया गया है, तो आप बहुत खराब हैं। स्ट्रीम का उपयोग करना काम नहीं करेगा क्योंकि थ्रेड अभी भी निष्पादन समाप्त होने तक अवरुद्ध है।

जिस समाधान पर मैंने मारा है, जो कुछ लोगों के लिए चरम लग सकता है लेकिन मुझे लगता है कि मेरे लिए काफी अच्छा काम करता है, दो ऐप्स के बीच विश्वसनीय सिंक्रोनस कॉमर्स सेट अप करने के लिए सॉकेट और मल्टीथ्रेडिंग का उपयोग करना है। बेशक, यह केवल तभी काम करता है जब आप दोनों ऐप्स को संलेखित कर रहे हों। यदि नहीं, तो मुझे लगता है कि आप भाग्य से बाहर हैं। ... मैं देखना चाहता हूं कि यह पारंपरिक धारा दृष्टिकोण का उपयोग करके सिर्फ मल्टीथ्रेडिंग के साथ काम करता है, इसलिए यदि कोई इसे आजमाकर परिणाम पोस्ट करना चाहेगा तो यह बहुत अच्छा होगा।

वैसे भी, यहाँ वर्तमान में मेरे लिए काम कर समाधान है:

मुख्य, या बुला एप्लिकेशन में, मैं कुछ इस तरह करते हैं:

/// <summary> 
/// Handles the OK button click. 
/// </summary> 
private void HandleOKButtonClick() { 
string executableFolder = ""; 

#if UNITY_EDITOR 
executableFolder = Path.Combine(Application.dataPath, "../../../../build/Include/Executables"); 
#else 
executableFolder = Path.Combine(Application.dataPath, "Include/Executables"); 
#endif 

EstablishSocketServer(); 

var proc = new Process { 
    StartInfo = new ProcessStartInfo { 
     FileName = Path.Combine(executableFolder, "WordConverter.exe"), 
     Arguments = locationField.value + " " + _ipAddress.ToString() + " " + SOCKET_PORT.ToString(), 
     UseShellExecute = false, 
     RedirectStandardOutput = true, 
     CreateNoWindow = true 
    } 
}; 

proc.Start(); 

यहाँ मैं कहाँ सॉकेट सर्वर स्थापित है:

/// <summary> 
/// Establishes a socket server for communication with each chapter build script so we can get progress updates. 
/// </summary> 
private void EstablishSocketServer() { 
    //_dialog.SetMessage("Establishing socket connection for updates. \n"); 
    TearDownSocketServer(); 

    Thread currentThread; 

    _ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]; 
    _listener = new TcpListener(_ipAddress, SOCKET_PORT); 
    _listener.Start(); 

    UnityEngine.Debug.Log("Server mounted, listening to port " + SOCKET_PORT); 

    _builderCommThreads = new List<Thread>(); 

    for (int i = 0; i < 1; i++) { 
     currentThread = new Thread(new ThreadStart(HandleIncomingSocketMessage)); 
     _builderCommThreads.Add(currentThread); 
     currentThread.Start(); 
    } 
} 

/// <summary> 
/// Tears down socket server. 
/// </summary> 
private void TearDownSocketServer() { 
    _builderCommThreads = null; 

    _ipAddress = null; 
    _listener = null; 
} 

धागे के लिए मेरा सॉकेट हैंडलर है ... ध्यान दें कि आपको कुछ मामलों में एकाधिक धागे बनाना होगा; यही कारण है कि मेरे पास है _builderCommThreads सूची वहाँ में (मैं इसे कोड से पोर्ट कहीं और जहां मैं ऐसी ही कुछ कर रहा था लेकिन एक पंक्ति में कई उदाहरण बुला) है:

/// <summary> 
/// Handles the incoming socket message. 
/// </summary> 
private void HandleIncomingSocketMessage() { 
    if (_listener == null) return; 

    while (true) { 
     Socket soc = _listener.AcceptSocket(); 
     //soc.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 10000); 
     NetworkStream s = null; 
     StreamReader sr = null; 
     StreamWriter sw = null; 
     bool reading = true; 

     if (soc == null) break; 

     UnityEngine.Debug.Log("Connected: " + soc.RemoteEndPoint); 

     try { 
      s = new NetworkStream(soc); 
      sr = new StreamReader(s, Encoding.Unicode); 
      sw = new StreamWriter(s, Encoding.Unicode); 
      sw.AutoFlush = true; // enable automatic flushing 

      while (reading == true) { 
       string line = sr.ReadLine(); 

       if (line != null) { 
        //UnityEngine.Debug.Log("SOCKET MESSAGE: " + line); 
        UnityEngine.Debug.Log(line); 

        lock (_threadLock) { 
         // Do stuff with your messages here 
        } 
       } 
      } 

      // 
     } catch (Exception e) { 
      if (s != null) s.Close(); 
      if (soc != null) soc.Close(); 
      UnityEngine.Debug.Log(e.Message); 
      //return; 
     } finally { 

     // 
     if (s != null) s.Close(); 
     if (soc != null) soc.Close(); 

     UnityEngine.Debug.Log("Disconnected: " + soc.RemoteEndPoint); 
     } 
    } 

    return; 
} 
बेशक

, आप कुछ सामान अप घोषित करने के लिए की आवश्यकता होगी शीर्ष पर:

private TcpListener _listener = null; 
private IPAddress _ipAddress = null; 
private List<Thread> _builderCommThreads = null; 
private System.Object _threadLock = new System.Object(); 

... तो लागू निष्पादन, दूसरे छोर की स्थापना में (मैं स्टैटिक्स इस मामले में प्रयोग किया जाता है, तो आप आप क्या कभी आप चाहते उपयोग कर सकते हैं):

private static TcpClient _client = null; 
private static Stream _s = null; 
private static StreamReader _sr = null; 
private static StreamWriter _sw = null; 
private static string _ipAddress = ""; 
private static int _port = 0; 
private static System.Object _threadLock = new System.Object(); 

/// <summary> 
/// Main method. 
/// </summary> 
/// <param name="args"></param> 
static void Main(string[] args) { 
    try { 
     if (args.Length == 3) { 
      _ipAddress = args[1]; 
      _port = Convert.ToInt32(args[2]); 

      EstablishSocketClient(); 
     } 

     // Do stuff here 

     if (args.Length == 3) Cleanup(); 
    } catch (Exception exception) { 
     // Handle stuff here 
     if (args.Length == 3) Cleanup(); 
    } 
} 

/// <summary> 
/// Establishes the socket client. 
/// </summary> 
private static void EstablishSocketClient() { 
    _client = new TcpClient(_ipAddress, _port); 

    try { 
     _s = _client.GetStream(); 
     _sr = new StreamReader(_s, Encoding.Unicode); 
     _sw = new StreamWriter(_s, Encoding.Unicode); 
     _sw.AutoFlush = true; 
    } catch (Exception e) { 
     Cleanup(); 
    } 
} 

/// <summary> 
/// Clean up this instance. 
/// </summary> 
private static void Cleanup() { 
    _s.Close(); 
    _client.Close(); 

    _client = null; 
    _s = null; 
    _sr = null; 
    _sw = null; 
} 

/// <summary> 
/// Logs a message for output. 
/// </summary> 
/// <param name="message"></param> 
private static void Log(string message) { 
    if (_sw != null) { 
     _sw.WriteLine(message); 
    } else { 
     Console.Out.WriteLine(message); 
    } 
} 

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

HTH

4

सही ढंग से संभालने के लिए उत्पादन और/या त्रुटि पुनर्निर्देशन आप भी इनपुट रीडायरेक्ट होना चाहिए। यह आपके द्वारा शुरू किए जा रहे बाहरी एप्लिकेशन के रनटाइम में फीचर/बग प्रतीत होता है और जो मैंने अभी तक देखा है, उससे कहीं और उल्लेख नहीं किया गया है।

उदाहरण उपयोग:

 Process p = new Process(...); 

     p.StartInfo.UseShellExecute = false; 
     p.StartInfo.RedirectStandardOutput = true; 
     p.StartInfo.RedirectStandardError = true; 
     p.StartInfo.RedirectStandardInput = true; // Is a MUST! 
     p.EnableRaisingEvents = true; 

     p.OutputDataReceived += OutputDataReceived; 
     p.ErrorDataReceived += ErrorDataReceived; 

     Process.Start(); 

     p.BeginOutputReadLine(); 
     p.BeginErrorReadLine(); 

     p.WaitForExit(); 

     p.OutputDataReceived -= OutputDataReceived; 
     p.ErrorDataReceived -= ErrorDataReceived; 

...

void OutputDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     // Process line provided in e.Data 
    } 

    void ErrorDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     // Process line provided in e.Data 
    } 
+1

मानक इनपुट के पुनर्निर्देशन ने मेरे लिए समस्या तय की। –

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