我试图在多个Process对象之间创建一个管道。
我可以运行单个Process并捕获其StandardOutput,但是当我尝试连接多个Process对象时,第二个似乎没有从第一个StandardInput接收任何数据。
在这段代码中,我使用cat
,它将其参数的内容打印到stdout,或者只是将stdin复制到stdout。
使用一个过程可以正常工作:
// Works
private async void launchButtonClicked(object sender, EventArgs e)
{
var outputBuffer = new MemoryStream();
var tasks = new List<Task>();
Process process1;
{
process1 = new Process();
process1.StartInfo.FileName = "cat.exe";
process1.StartInfo.Arguments = "K:\\temp\\streams.txt";
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.RedirectStandardOutput = true;
process1.StartInfo.RedirectStandardInput = false;
process1.StartInfo.CreateNoWindow = true;
process1.EnableRaisingEvents = true;
process1.Start();
}
tasks.Add(process1.StandardOutput.BaseStream.CopyToAsync(outputBuffer));
await Task.WhenAll(tasks);
// OK: This prints the contents of the file
Console.WriteLine("Final output: {0}", UTF8Encoding.UTF8.GetString(outputBuffer.GetBuffer()));
}
但是当我添加第二个进程并尝试将Process1的StandardOutput复制到Process2的StandardInput时,我从来没有从Process2获得任何输出并且await永远不会完成:
// Doesn't work
private async void launchButtonClicked(object sender, EventArgs e)
{
var outputBuffer = new MemoryStream();
var tasks = new List<Task>();
Process process1, process2;
{
process1 = new Process();
process1.StartInfo.FileName = "cat.exe";
process1.StartInfo.Arguments = "K:\\temp\\streams.txt";
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.RedirectStandardOutput = true;
process1.StartInfo.RedirectStandardInput = false;
process1.StartInfo.CreateNoWindow = true;
process1.Start();
}
{
process2 = new Process();
process2.StartInfo.FileName = "cat.exe";
process2.StartInfo.Arguments = "";
process2.StartInfo.UseShellExecute = false;
process2.StartInfo.RedirectStandardOutput = true;
process2.StartInfo.RedirectStandardInput = true;
process2.StartInfo.CreateNoWindow = true;
process2.Start();
}
tasks.Add(process1.StandardOutput.BaseStream.CopyToAsync(process2.StandardInput.BaseStream));
tasks.Add(process2.StandardOutput.BaseStream.CopyToAsync(outputBuffer));
await Task.WhenAll(tasks); // Never returns!
Console.WriteLine("Final output: {0}", UTF8Encoding.UTF8.GetString(outputBuffer.GetBuffer()));
}
通过命令行执行此类操作可以正常工作:
C:\>cat.exe K:\temp\streams.txt | cat.exe
... contents of file ...
C:\>
我尝试将Exited事件处理程序添加到这些Process对象。 Process1退出正常,但Process2永不退出。
我也尝试了其他一些命令(比如sed),但Process2似乎仍然没有做任何事情。
我正在使用溪流&#39; BaseStream属性,因为我最终将使用二进制数据。 (https://stackoverflow.com/a/4535927/339378)这也意味着我无法使用OutputDataReceived
,它会返回一个字符串(无论如何都会更复杂)。
谢谢!
答案 0 :(得分:3)
显然,CopyToAsync
在完成时不会关闭输出流。这对我的MemoryStream来说无关紧要,但显然我需要关闭一个进程的StandardInput,否则它将无法完成。
我制作了这个方法:
private static async Task CopyThenClose(Stream from, Stream to)
{
await from.CopyToAsync(to);
to.Close();
}
取代了对CopyToAsync
的电话;例如:
tasks.Add(CopyThenClose(process1.StandardOutput.BaseStream, process2.StandardInput.BaseStream));