将Process StandardOutput连接到另一个Process StandardInput
本文关键字:Process 另一个 StandardInput 连接 StandardOutput | 更新日期: 2023-09-27 18:22:38
我正在尝试在几个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获得任何输出,等待也从未完成:
// 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似乎仍然什么都没做。
我使用流的BaseStream属性,因为我最终将使用二进制数据。(https://stackoverflow.com/a/4535927/339378)这也意味着我不能使用OutputDataReceived
,它返回一个字符串(无论如何都会更复杂)。
谢谢!
显然,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));