2009-08-14 21 views
1

我從C#應用程序啓動另一個進程,並出現問題:有什麼方法可以讀取進程輸出char-by-char,而不是逐行嗎?我非常需要這樣做,因爲另一個進程是一個命令行引擎,我需要向它發送一個命令,讀取輸出並以某種方式理解它何時完成。它表示的方式是在沒有換行的情況下編寫提示,所以我沒有機會捕捉到它。現在使用易碎定時器的東西,並尋找更好的解決方案。.NET IO重定向 - 通過字符讀取輸出字符

MSDN中概述的C#過程API和other places只允許逐行輸入 - 即使採用異步方式。

回答

1

我還沒有嘗試過,但下面的方法可能工作,以避免忙循環:

  1. 重定向命令行輸出到一個文件。
  2. 使用Win32 API中的FindFirstChangeNotification(標誌爲FILE_NOTIFY_CHANGE_SIZE)來檢測文件大小更改。

但是,爲防止繁忙的循環,這是一項非常多的工作。就個人而言,我會建議一個增量退避等待循環,以防止使用太多的系統資源。類似於(僞代碼):

int waittime = 1; 
bool done = false; 
while (true) 
{ 
    ReadAsMuchAsIsAvailable(); 
    if (TheAvailableOutputEndsInAPrompt()) 
    { 
    break; 
    } 
    Sleep (waittime); 
    waittime++;      // increase wait time 
    waittime = min(waittime, 1000); // max 1 second 
} 

這將對快速命令產生快速的操作結束檢測,對於慢速命令則產生較慢的結果。這意味着您可以執行大量的快速命令並快速檢測它們的結束,而較長的命令可能會有1秒的開銷(考慮到命令本身的大小,這不會引人注意)。

+0

謝謝,這是我最終完成的(增量退避等待循環)。推出這個循環作爲一個單獨的線程,它現在很好地工作。 – 2009-08-17 20:06:15

0

這是一個啓動的過程的示例程序中,並通過線由字符讀取標準輸出,字符和不行:

static void Main(string[] args) 
    { 
     var process = new Process(); 
     process.StartInfo = new ProcessStartInfo(@"C:\Windows\System32\cmd.exe", "/c dir"); 
     process.StartInfo.UseShellExecute = false; 
     process.StartInfo.RedirectStandardOutput = true; 
     process.Start(); 
     var outReader = process.StandardOutput; 
     while (true) 
     { 
      if (!outReader.EndOfStream) 
       Console.Write((char)outReader.Read() + "."); 
      if (outReader.EndOfStream) 
       Thread.Sleep(1); 
     } 
    } 

小聲明 - 這是在沒有時間敲起來,並且我沒有證明有關時間的問題(如果在我們抓住標準輸出之前流程退出 - 我知道這種情況不太可能發生)。但是,就你的特定問題而言,它表明一個人不需要逐行閱讀(畢竟你是在處理一個StreamReader)。

更新:根據建議,包括一個Thread.Sleep(1)產生線程。顯然有使用Thread.Sleep(0),儘管關於此事的MSDN文檔(較低優先級的線程沒有給出時間)的問題。並且是的,這是一個無限循環,並且必須有一些線程管理的東西來完成這個過程。

+0

這需要一個單獨的線程來始終檢查EndOfStream屬性,這是高CPU佔用率的一種方式。我正在尋找一種方式讓流在新的字節到達時通知我 - 任何想法? – 2009-08-14 09:37:13

+0

我可能會做類似的事情。也許加入一個小小的睡眠,並將其放入NewChar事件或類似的課程中。 – Svish 2009-08-14 10:10:39

+0

是否有任何理由不能只使用StreamReader的BaseStream屬性,並使用BeginRead和EndRead方法在異步莊園中執行此操作? – 2013-11-08 01:31:06

0
char[] x = {' '}; 

System.IO.StreamReader reader = new StreamReader("c:\\file.txt"); 



     while (!reader.EndOfStream) 
     { 
      reader.ReadBlock(x, 0, 1);  
      // x contains the current char in the reader.    
     } 

這應該有效。

編輯:

那麼如何有關使用此:

x = reader.ReadToEnd().ToCharArray(); 
+0

與以前相同的評論 - 我需要始終調用EndOfStream來檢查是否有新數據到達。在這裏尋找更聰明的方法.. – 2009-08-14 09:44:20

+0

ReadToEnd()將阻止執行,直到流被關閉......這不是我所需要的。 – 2009-08-14 16:02:14

相關問題