【发布时间】:2011-09-29 13:21:08
【问题描述】:
我正在尝试更改与 Mercurial 命令行客户端对话的类库,而 1.9 客户端中的新功能是能够启动服务器并通过标准输入/输出管道与其对话。这确实很有希望,因为使用 Mercurial 命令行客户端的主要问题之一是,由于它是用 Python 编写的,因此启动客户端会产生一些开销,即使只是询问它的版本也是如此。
但是,有一个问题。到目前为止,我已经通过读取标准输出/错误从命令行客户端检索输出,当进程退出时,流刷新并且我可以读取流的结尾。
但是,在这种新模式下,进程会将大量文本转储到标准错误/输出,然后等待下一个命令。非常适合减少开销,但很糟糕,因为 .NET 缓冲了这些流。
换句话说,由于进程没有退出,所以直到:
- 我要求进程退出
- 我发出另一个命令
有没有办法让我
- 请求缓冲区刷新,这意味着我得到缓冲区中的任何内容,即使它不足以使缓冲区自行刷新?
- 如果不是,我可以将缓冲区大小设置为 1 个字符吗?
- 我还能做什么?
如果需要的话,我可以处理 P/Invoke。
这是一个 LINQPad 概念验证程序,可以说明:
它的作用是启动命令提示符并将 DIR 命令提供给它,但是请注意,直到循环内的那 10 秒过去后,程序才会输出命令提示符后立即输出的“C:>”提示符生成目录列表。
换句话说,这就是命令提示符的作用:
- 制作目录列表
- 通过提示“C:>\”请求另一个命令
但是,下面的程序看到的是这样的:
- 制作目录列表
- (等待 10 秒)
- 关闭输入流
-
查看提示
void Main() { string 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);}
【问题讨论】:
-
我改程序去掉了对Mercurial的依赖,现在用常规的CMD.EXE程序来说明。
-
您好,我也遇到了同样的问题,您解决了吗?如果是这样,怎么办? :)
标签: .net process buffer redirectstandardoutput