2012-01-10 96 views
17

我的項目中存在問題。我想啓動一個進程,7z.exe(控制檯版本)。 我試過三種不同的東西:從流程獲取實時輸出

  • Process.StandardOutput.ReadToEnd();
  • OutputDataReceived & BeginOutputReadLine
  • 的StreamWriter

沒有什麼工作。它總是「等待」流程的結束,以顯示我想要的。 我沒有任何代碼要放,只要你想要我的代碼與上面列出的東西之一。謝謝。

編輯: 我的代碼:

 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函數而不使用7z.exe的方法(可能使用7za.exe或某些DLL)。謝謝大家。 要回答這個問題,OuputDataRecieved事件工作正常!

+0

任何你不使用7zip中的DLL/SDK downloadabe的原因,它允許比任何基於控制檯的技術更好的控制嗎? – Yahia 2012-01-10 18:44:39

+0

這將有助於查看您嘗試使用的流程的代碼,例如您在何處創建流程 – MethodMan 2012-01-10 18:56:40

+0

因爲7z.exe涵蓋了我想要的所有功能。 – Extaze 2012-01-10 20:22:21

回答

16

看看這個頁面,看起來這是你的解決方案:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.beginoutputreadline.aspxhttp://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(); 

Btw,ls -R C:\遞歸列出C:根的所有文件。這些是很多文件,並且我確信在屏幕上顯示第一個結果時它不會完成。 在顯示它之前,7zip有可能保留輸出。我不確定你給這個過程的參數。

+0

看我的代碼:/ – Extaze 2012-01-10 20:50:59

+0

我所能找到的,是你應該使用的事件OutputDataReceived,目前我沒有時間測試它,也許以後。 (http://harbertc.wordpress.com/2006/05/16/reading-text-from-a-process-executed-programmatically-in-c/) – 2012-01-11 18:50:29

+0

我試了一切,但問題是7z.exe。我決定爲c#(SevenZipSharp)購買一個7z庫,問題就解決了。謝謝;) – Extaze 2012-01-22 10:19:07

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

就像我看到的那樣,這段代碼也會等到它完成。正如問題所述,他不想等到它完成,但想要現場輸出 – 2012-01-10 19:05:05

+0

正如Michiel所說,那是爲了得到「最終」輸出 – Extaze 2012-01-10 20:50:28

1

我在幾個項目中使用了CmdProcessor類描述here,並取得了很大的成功。它看起來有點令人生畏,但使用起來非常簡單。

+0

不起作用...它等待進程停止向我顯示信息... – Extaze 2012-01-10 20:50:04

4

我不知道是否有人還在尋找一個解決方案,這一點,但它已經好幾次對我來說,因爲我支持的一些遊戲,並且由於寫在Unity的工具,以有限的互操作性與單某些系統(如PIA從Word中閱讀文本,例如),我經常寫OS專用(有時的Windows,MacOS的有時)的可執行文件,並從推出的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(); 

這裏就是我建立socket服務器:

/// <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); 
    } 
} 

。 ..一世' m使用它在Windows上啓動一個命令行工具,該工具使用PIA將文本從Word文檔中提取出來。我嘗試了PIA Unity中的.dll,但遇到了單聲道的互操作問題。我還在MacOS上使用它來調用shell腳本,這些腳本以batchmode方式啓動其他Unity實例,並在那些通過此套接字連接與工具交談的實例中運行編輯器腳本。這很好,因爲我現在可以向用戶發送反饋,調試,監視和響應該過程中的特定步驟等等。

HTH

4

要正確處理輸出和/或錯誤重定向,還必須重定向輸入。 它似乎是在開始的youre外部應用程序的運行時間,從我迄今所看到的特性/錯誤,它沒有提到其他地方。

用法示例:

 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

標準輸入的重定向爲我解決了問題。 – 2016-02-01 10:15:31