ProcessInfo и RedirectStandardOutput
У меня есть приложение, которое вызывает другой процесс в окне команды, и этот процесс имеет статистику обновления, которая выводится в окно консоли. Я думал, что это довольно простая операция, но я не могу заставить ее работать. Я что-то упускаю?
string assemblyLocation = Assembly.GetExecutingAssembly().Location;
Process process = new Process
{
ProcessStart =
{
RedirectStandardOutput = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = arg,
FileName = assemblyLocation.Substring(0, assemblyLocation.LastIndexOf("")) + "ffmpeg.exe",
CreateNoWindow = true
}
};
process.Start();
Console.WriteLine(process.StandardOutput.ReadToEnd());
process.WaitForExit();
В идеале то, что я хотел бы, это как выходные изменения в этом процессе, который я нажал или данные поступают в читатель, что я получаю события от него.
любая помощь будет большое, я чувствую, что это вопрос новичка, но, кажется, что-то упустить.
6 ответов
Я уже испытывал это раньше. Иногда способ, которым процесс, который вы вызываете выходы на консоль, несовместим с таким перенаправлением вывода. Мне повезло, что в этом случае я смог изменить внешний процесс, чтобы обойти это.
вы можете попробовать запустить свой код в другом процессе, который выводит на консоль, и посмотреть, работает ли он правильно. Это читается прямо сейчас.
EDIT:
Я пошел и вытащил кодовый блок, который я использовал для этого. Это в приложении WPF, которое перенаправляет вывод процесса в окно. Обратите внимание на привязку события. Поскольку это WPF, я должен вызвать свой вызов для записи данных. Поскольку вы не беспокоитесь о блокировке, ou должен быть в состоянии просто заменить это на:
Console.WriteLine(e.Data);
надеюсь, что это помогает!
private static void LaunchProcess()
{
Process build = new Process();
build.StartInfo.WorkingDirectory = @"dir";
build.StartInfo.Arguments = "";
build.StartInfo.FileName = "my.exe";
build.StartInfo.UseShellExecute = false;
build.StartInfo.RedirectStandardOutput = true;
build.StartInfo.RedirectStandardError = true;
build.StartInfo.CreateNoWindow = true;
build.ErrorDataReceived += build_ErrorDataReceived;
build.OutputDataReceived += build_ErrorDataReceived;
build.EnableRaisingEvents = true;
build.Start();
build.BeginOutputReadLine();
build.BeginErrorReadLine();
build.WaitForExit();
}
// write out info to the display window
static void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
string strMessage = e.Data;
if (richTextBox != null && !String.Empty(strMessage))
{
App.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate()
{
Paragraph para = new Paragraph(new Run(strMessage));
para.Margin = new Thickness(0);
para.Background = brushErrorBrush;
box.Document.Blocks.Add(para);
});
}
}
Я не уверен, с какой именно проблемой вы столкнулись, но если вы хотите действовать на выходе, как только он будет сгенерирован, попробуйте подключиться к процессу OutputDataReceived
событие. Можно указать обработчики для асинхронного получения выходных данных из процесса. Я успешно использовал этот подход.
ProcessStartInfo info = new ProcessStartInfo(...)
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
Process p = Process.Start(info);
p.OutputDataReceived += p_OutputDataReceived;
p.ErrorDataReceived += p_ErrorDataReceived;
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
..
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Received from standard out: " + e.Data);
}
void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Received from standard error: " + e.Data);
}
посмотреть OutputDataReceived event off Process для получения дополнительной информации.
С помощью лямбда-выражений и т. д.:
var info = new ProcessStartInfo(path)
{
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
Verb = "runas",
};
var process = new Process
{
EnableRaisingEvents = true,
StartInfo = info
};
Action<object, DataReceivedEventArgs> actionWrite = (sender, e) =>
{
Console.WriteLine(e.Data);
};
process.ErrorDataReceived += (sender, e) => actionWrite(sender, e);
process.OutputDataReceived += (sender, e) => actionWrite(sender, e);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
интересно, что вы не можете читать из стандартного вывода и стандартной ошибки одновременно:
Если вы перенаправляете как стандартный вывод, так и стандартную ошибку, а затем пытаетесь прочитать оба, для пример использования следующего кода C#.
[C#]
выходная строка = стр. StandardOutput.ReadToEnd();
ошибка строка = стр. StandardError.ReadToEnd();
п.WaitForExit();
в этом случае, если ребенок процесс записывает любой текст в стандартную ошибку, он блокирует процесс, потому что родительский процесс не может считывать из стандартной ошибки, пока он не закончит чтение от стандартного выхода. Однако, родительский процесс не будет читать из стандартного вывод до завершения процесса. Рекомендуемое решение этой ситуации-создать два потоки, чтобы ваше приложение могло считывать выходные данные каждого потока на отдельном нитка.
текущий код работал в VS2010
void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (String.IsNullOrEmpty(e.Data) == false)
{
new Thread(() =>
{
this.Dispatcher.Invoke(new Action(() =>
{
// Add you code here
}));
}).Start();
}
}
проверьте, что выход, который вы ожидаете, не отправляется на выход StandardError вместо выхода StandardOutput