获取.NET Process对象以连续刷新输入流? [英] Get .NET Process object to flush input stream continously?
问题描述
我正在尝试更改与Mercurial命令行客户端通信的类库,而1.9客户端的新功能是能够启动服务器并通过标准输入/输出管道与之对话.这确实是有希望的,因为使用Mercurial命令行客户端的主要麻烦之一是,由于它是用Python编写的,因此即使只是询问其版本,该客户端也有一些开销.
I am trying to change my class library that talks to the Mercurial command line client, and new in the 1.9 client is the ability to spin up a server and talk to it over the standard input/output pipes. This is really promising since one of the major headaches of using the Mercurial command line client is that since it is written in Python, there's a bit of overhead spinning up the client, even for just asking it for its version.
但是,有一个问题.到目前为止,我已经通过读取标准输出/错误从命令行客户端检索了输出,并且当进程退出时,流将刷新,并且我可以读取流的末尾.
However, there is one problem. Up until now I have retrieved the output from the command line client by reading the standard output/error, and when the process exits, the streams flush and I can read the end of the stream.
但是,在这种新模式下,该过程会将大量文本转储到标准错误/输出中,然后坐在那里等待下一个命令.很棒,可以减少开销,但是由于.NET缓冲了这些流,所以很糟糕.
However, in this new mode, the process will dump a lot of text to the standard error/output, and then sit around waiting for the next command. Great for reducing overhead, but lousy since .NET buffers those streams.
换句话说,由于该过程不会退出,因此直到以下情况我才得到该输出的最后一部分:
In other words, since the process does not exit, I do not get the last portion of that output until:
- 我要求退出流程
- 我发出另一个命令
我有办法吗
- 询问要刷新的缓冲区,这意味着即使缓冲区不足以自己刷新也可以获得缓冲区中的所有内容?
- 如果没有,我可以将缓冲区大小设置为1个字符吗?
- 我还能做什么?
如果需要的话,我可以处理P/Invoke.
I can deal with P/Invoke if that is what it takes.
这是一个 LINQPad 概念验证程序,该程序将说明:
Here's a LINQPad proof-of-concept program that would illustrate:
它的作用是旋转命令提示符并向其提供DIR命令,但是请注意,直到循环内经过10秒钟,程序才输出"C:>"提示符,命令提示符紧随其后输出产生目录清单.
What it does is spin up a command prompt and feed it the DIR command, however notice that not until those 10 seconds have elapsed inside the loop does the program output the "C:>" prompt that the command prompt outputted right after producing the directory listing.
换句话说,这就是命令提示符的作用:
In other words, this is what the command prompt does:
- 生成目录列表
- 通过提示"C:> \"询问另一个命令
但是,这是下面的程序所见:
However, this is what the program below sees:
- 生成目录列表
- (等待10秒)
- 关闭输入流
-
查看提示
- Produce directory listing
- (wait 10 seconds)
- Close the input stream
See the prompt
void Main() { 字符串clientExecutablePath ="cmd.exe";
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);
}
推荐答案
我认为没有任何方法可以强制进行冲洗,但是我有几种替代方法可能会对您有所帮助:
I don't think there's any way to force a flush, however I have a couple of alternatives which might help you:
- 我注意到您正在使用ReadLine()读取流.在写入完整的输出行(包括CRLF或至少LF)之前,此操作不会返回.因此,您可能需要考虑使用Read()代替,后者将仅读取单个字符.如果服务器进程在退出前没有在最后一行写CRLF,则可能会找到所需的最后一块输出.
- 您可以通过将处理程序添加到Process上的OutputDataReceived和ErrorDataReceived事件来异步读取流,然后使用BeginOutputReadLine和BeginErrorReadLine开始接收数据.我不知道这些事件被调用的频率:每隔一定的间隔,是否有可用的数据,何时接收到完整的数据行,或每个字符.
HTH,
巴特
这篇关于获取.NET Process对象以连续刷新输入流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!