Я пытаюсь создать конвейер между несколькими объектами Process.Подключить процесс StandardOutput к другому стандарту ProcessInput
Я могу запустить один процесс и захватить его стандартный вывод, но когда я пытаюсь подключить несколько объектов Процесса, второй, похоже, не получает никаких данных из первого стандартного ввода.
В этом коде я использую cat
, который либо печатает содержимое своих аргументов в стандартном режиме, либо просто копирует 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()));
}
Но когда я добавить второй процесс и попытаться скопировать StandardOutput process1 на StandardInput Process2, я никогда не получить какой-либо выход из 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 обработчики событий. Process1 выходит из строя, но Process2 никогда не выходит.
Я также пробовал некоторые другие команды (например, sed), но Process2 все еще ничего не делает.
Я использую свойства базового потока streams, потому что в конечном итоге я буду работать с двоичными данными. (https://stackoverflow.com/a/4535927/339378) Это также означает, что я не могу использовать OutputDataReceived
, который возвращает строку (и это было бы все равно сложнее).
Спасибо!
вы можете настроить свой вход и выход процесса перед запуском начала – gashach
@gashach Вы не можете использовать StandardOutput/Input перед началом процесса или вы получите исключение: «StandardOut не был перенаправлен или процесс еще не начался ». – mrb
нормально, как насчет использования стандартного свойства на process2? – gashach