2011-07-06 31 views
2

我正在嘗試更改我的類庫以與Mercurial命令行客戶端通信,而1.9客戶端中的新增功能是啓動服務器並通過標準輸入/輸出管道與其通信。這是非常有前途的,因爲使用Mercurial命令行客戶端的主要問題之一是,因爲它是用Python編寫的,所以在客戶端上花費一些開銷,即使只是要求它的版本。獲取.NET Process對象以連續刷新輸入流?

但是,有一個問題。到目前爲止,我已經通過讀取標準輸出/錯誤來從命令行客戶端獲取輸出,並且當進程退出時,流將刷新,並且我可以讀取流結束。

但是,在這種新模式下,進程會將大量文本轉儲到標準錯誤/輸出中,然後等待下一個命令。非常適合減少開銷,但由於.NET緩衝了這些流,所以很糟糕。

換句話說,因爲過程不退出,我不明白的是輸出的,直到最後一個部分:

  1. 請問進程退出
  2. 我發出另一個命令

有沒有辦法讓我

  1. 問緩衝刷新,這意味着我得到無論是在緩衝區,EV如果它不足以使緩衝區自行刷新?
  2. 如果不是,我可以設置緩衝區大小爲1個字符嗎?
  3. 我還能做什麼?

如果這是需要的,我可以處理P/Invoke。

這裏有一個LINQPad驗證的概念方案,將說明:

它是什麼旋轉了一個命令提示符,然後餵給它的DIR命令,但是請注意,直到這10秒內環路經過程序是否輸出在生成目錄列表後立即輸出命令提示符的「C:>」提示符。

換句話說,這是命令提示符的作用:

  1. 農產品目錄列表
  2. 向另一個命令通過提示 「C:> \」

然而,這是什麼下面的程序看:

  1. 農產品目錄列表
  2. (等待10秒)
  3. 關閉輸入流
  4. 看到提示

    無效的主要() { 串clientExecutablePath =「CMD。exe文件「;

    var psi = new ProcessStartInfo(); 
    psi.FileName = clientExecutablePath; 
    psi.RedirectStandardError = true; 
    psi.RedirectStandardInput = true; 
    psi.RedirectStandardOutput = true; 
    psi.CreateNoWindow = true; 
    psi.WorkingDirectory = @"C:\"; 
    psi.WindowStyle = ProcessWindowStyle.Hidden; 
    psi.UseShellExecute = false; 
    psi.ErrorDialog = false; 
    psi.StandardErrorEncoding = Encoding.GetEncoding("Windows-1252"); 
    psi.StandardOutputEncoding = Encoding.GetEncoding("Windows-1252"); 
    
    var p = Process.Start(psi); 
    
    var input = p.StandardInput; 
    var output = p.StandardOutput; 
    var error = p.StandardError; 
    
    Action<StreamReader, string> reader = delegate(StreamReader streamReader, string prefix) 
    { 
        string line; 
        while ((line = streamReader.ReadLine()) != null) 
        { 
         Debug.WriteLine(prefix + line); 
        } 
    }; 
    
    IAsyncResult outputReader = reader.BeginInvoke(output, "o: ", null, null); 
    IAsyncResult errorReader = reader.BeginInvoke(error, "e: ", null, null); 
    
    input.Write("dir\n"); 
    input.Flush(); 
    
    while (!p.HasExited) 
    { 
        Thread.Sleep(10000); 
        input.Close(); 
    } 
    
    reader.EndInvoke(outputReader); 
    reader.EndInvoke(errorReader); 
    

    }

+0

我改變了計劃砸水銀的依賴,現在它使用常規的CMD.EXE程序來說明。 –

+0

嗨,我在這裏遇到同樣的問題,你是否設法完成它?如果是這樣,怎麼樣? :) – FrieK

回答

1

我不認爲有任何的方式來強制刷新,但是我有幾個選擇這可能會幫助您:

  1. 我注意你使用ReadLine()來讀取流,直到完整的輸出行(包括CRLF,或者至少LF)被寫入後纔會返回,所以你可能想要考慮使用Read()來代替,將只能讀取一個字符,您可能會發現這會讓您感到厭倦如果服務器進程在最後一行沒有寫出CRLF直到它退出,那麼他將查找最後一批輸出。
  2. 您可以通過將處理程序添加到Process上的OutputDataReceived和ErrorDataReceived事件來異步讀取流,然後使用BeginOutputReadLine和BeginErrorReadLine開始接收數據。我不知道事件被調用的頻率如何:每隔一段時間收到一整行數據或每個字符時,定期收集數據。

HTH,

巴特

+0

我會嘗試兩個! –

+0

當然,現在你提到它可能是一個完全自行設置的緩衝區,一條完整的行:P由於Mercurial命令客戶端的輸出無論如何都會在中間產生一些時髦字符,所以它會說「o <字節編碼int> characters「,我需要去除那些字節,我只是假設緩衝區在流中,但當然ReadLine中也有一個,也許如果我剛剛寫了我的代碼來讀取該輸出以開始它如果沒有我知道其中的差異,我會工作的。 –