2011-09-30 86 views
4

問候計算器件,輸出解析更新單個控制檯線路

在WPF前端的一個BackgroundWorker

我運行在一個System.Diagnostics.Processsox(開源控制檯聲音處理工具)。以同樣的方式,我使用其他幾個命令行工具並解析它們的輸出以在我的前端填充進度條。

這適用於其他工具,但不適用於Sox,因爲它不是爲每個進度步驟發送新行,而是通過僅使用回車符(\ r)和沒有換行符(\ n)更新控制檯上的一行)。我在process.StandardError上嘗試了異步和同步讀取。

結合使用異步process.ErrorDataReceived += (sender, args) => FadeAudioOutputHandler(clip, args);process.BeginErrorReadLine();不會產生任何的個人狀態更新,因爲某些原因,回車不觸發的ReadLine,即使MSDN docs認爲它應該。當過程完成時,輸出會在一個塊中吐出。

我然後通過炭嘗試了同步炭以下代碼讀取的流:

char[] c; 
var line = new StringBuilder(); 
while (process.StandardError.Peek() > -1) 
{ 
    c = new char[1]; 
    process.StandardError.Read(c, 0, c.Length); 
    if (c[0] == '\r') 
    { 
     var percentage = 0; 
     var regex = new Regex(@"%\s([^\s]+)"); 
     var match = regex.Match(line.ToString()); 
     if (match.Success) 
     { 
      myProgressObject.ProgressType = ProgressType.FadingAudio 
      //... some calculations omitted for brevity 
      percentage = (int) Math.Round(result); 
     } 
     else 
     { 
      myProgressObject.ProgressType = ProgressType.UndefinedStep; 
     } 
     _backGroundWorker.ReportProgress(percentage, myProgressObject); 
     line.Clear(); 
    } 
    else 
    { 
     line.Append(c[0]); 
    } 
} 

上面的代碼似乎不讀取實時數據流,但將停止輸出一會兒。然後它會傳播一個小塊,最終在整個過程中發生死鎖。

任何提示朝着正確的方向將不勝感激!

更新與(不拘小節?)解決方案:

這讓我抓狂,因爲沒有什麼我想對事物的C#方似乎對結果產生任何影響。我最初的實現,在改變它15次並引入新的依賴之前,沒有問題。

問題在於單獨使用sox和RedirectStandardError。我發現在獲取sox源代碼並構建自己的版本之後。首先我完全刪除了sox的所有輸出,除了我真正感興趣的東西,然後將輸出更改爲全行,然後換行符\n。我認爲這會解決我的問題。那麼,它沒有。我不知道足夠的C++來找出原因,但他們似乎已經緩和了stdio如何寫入該流,如何緩衝或以如此特殊的方式執行,以至於c#端的streamreader不會刷新到默認值4096字節緩衝區已滿。我確認通過填充每行至少4096字節。所以在最後我所要做的就是手動沖水標準錯誤中sox.c每個fprintf(stderr, ...)通話後display_status(...)

fflush(stderr); 

雖然,我不知道這是任何接近一個完美的解決方案。

感謝Erik Dietrich的回答,這讓我從不同的角度來看待這個問題。

+0

關於sox的信息讓我感到好奇,所以我做了一些調查。這可能是一個遠射,但http://en.wikipedia.org/wiki/Setvbuf有有趣的可能性。它看起來像你可以通過文件句柄強制緩衝設置,而不是通過進程。這可以讓你'重寫'sox的默認行爲,這樣你就可以獨立保存它的源代碼,而不會在每次更新它們的東西時註定要手動更新。可能有一個託管的C#等價物,或者你可以只寫一個調用一個微小的C實用程序。 –

回答

9

您所描述的情況是一個已知的問題 - 對包括源代碼的解決方案看http://www.codeproject.com/KB/threads/ReadProcessStdoutStderr.aspx

它解決了這兩個問題(死鎖,並與\n問題)......

+0

謝謝你的回答。我使用鏈接上的ProcessIoManager嘗試了相同的結果。輸出在開始時掛起,然後輸出以塊的形式出現,每個塊都有5秒的延遲。如果我使用鏈接中的示例gui和sox結合使用,也會發生同樣的情況。 RedirectStandardError和sox輸出似乎存在問題。在命令行上運行sox不會顯示這些症狀。 – Till

+0

5秒延遲是流式緩衝區緩衝區填滿的時間,如果感興趣,請查看我更新的問題。 – Till

+0

感謝您的更新......您描述它的方式是依賴於實現的,所以除了更改SOX之外,我沒有看到任何其他選項,因爲存在實現導致此行爲的實現,並且接受方的任何內容都無法更改。 – Yahia

2

我不得不處理與Visual Studio中的定製構建工具類似的問題。我發現使用正則表達式並在與讀取相同的線程中進行解析是一個問題,輸出處理停止。我最終提供了一個標準的消費者生產者解決方案,您可以從輸出中讀取行並將其粘貼到隊列中。然後讓隊列出列並在其他某個線程上處理。我不能提供源代碼,但這個網站有一些精彩的資源:http://www.albahari.com/threading/part2.aspx

+0

這似乎並不是一個問題,即使在註釋了狀態更新的間隔檢查後,每分鐘會產生幾千行,正則表達式部分也不會引起任何問題。 – Till

2

這是一個有點缺憾,但也許你可以管的不合作過程的輸出到一個過程,什麼也不做,但過程中輸入的字符,插入線飼料,並寫入到標準輸出。所以,在(非常)僞碼方面:

StartProcess("sox | littleguythatIwrote") 
ReadStandardOutTheWayYouAleadyAre() 

難道說只是移動球門柱(我有很多性病/出更熟悉/ Nr世界中的錯誤),但無論如何,這是查看問題的另一種方式。

+0

謝謝你讓我檢查東西的sox邊。如果您有興趣,請查看我的最新問題。 – Till

+0

嗯......有趣。我想知道是否可以以某種方式代表另一個進程清除標準錯誤(似乎不太可能,但是誰知道?)。我能想到的唯一方法是以某種方式欺騙sox,認爲它與用戶交互。如果內存服務,如果STD I/O的C庫認爲它們是由用戶直接調用的,則它們的行爲會有所不同。但是再一次,Linux上的內存就是C,所以要拿下一點鹽。 –