如何在C#应用1中实时读取C#控制台应用2的周期性标准输出?
实时读取控制台应用输出的解决方案
核心问题分析
原来的代码依赖StandardOutput.ReadToEnd()和WaitForExit(),这两个方法都会阻塞直到应用2完全退出,自然无法实时捕获周期性输出。要实现实时读取,必须改为异步监听进程的输出事件,而非等待进程结束后一次性获取数据。
应用1修改方案(实时读取版本)
通过绑定Process.OutputDataReceived事件异步捕获每一行输出,同时添加超时控制确保20秒后自动终止进程并清理资源。示例代码如下:
private Process Process_app2; private CancellationTokenSource _cts; // 用于控制20秒运行时长 public async Task Read_Std_Output_Realtime() { _cts = new CancellationTokenSource(); Process_app2 = new Process { StartInfo = new ProcessStartInfo { FileName = app2_path, Arguments = arguments, UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true, StandardOutputEncoding = Encoding.UTF8 // 统一编码避免乱码 } }; // 绑定输出接收事件,实时处理每一行数据 Process_app2.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) { // 这里替换成你的业务逻辑,比如更新UI、存储数值等 Console.WriteLine($"实时收到:{e.Data}"); item_value = e.Data; } }; Process_app2.Start(); Process_app2.BeginOutputReadLine(); // 启动异步读取循环 // 等待20秒后终止进程 try { await Task.Delay(TimeSpan.FromSeconds(20), _cts.Token); } catch (TaskCanceledException) { // 正常取消,无需额外处理 } finally { // 停止监听并清理资源 Process_app2.CancelOutputRead(); if (!Process_app2.HasExited) { Process_app2.Kill(); Process_app2.WaitForExit(); } Process_app2.Dispose(); _cts.Dispose(); } }
关键改动说明
- 用
OutputDataReceived事件替代ReadToEnd(),实现异步实时捕获输出 - 调用
BeginOutputReadLine()启动持续的异步读取循环 - 新增
CancellationTokenSource控制20秒运行时长,到点后自动终止应用2 - 指定
StandardOutputEncoding确保和应用2的输出编码一致,避免乱码
应用2优化建议
原代码中的Console.Clear()会输出控制字符(如ESC清屏指令),这些字符会被应用1读取到,导致无效数据。建议移除该方法,并添加循环次数限制确保进程运行20秒后自动退出:
static void Main(string[] args) { int runCount = 0; // 限制运行20次(每秒1次) while (runCount < 20) { // 替换成你的数值生成逻辑 var item_value_output = new Random().Next(1, 100); Console.WriteLine(item_value_output); Console.Out.Flush(); // 强制刷新输出缓冲区,确保数据立即发送 System.Threading.Thread.Sleep(1000); runCount++; } }
应用2关键优化
- 移除
Console.Clear(),避免输出无效控制字符 - 添加循环次数限制,确保进程运行20秒后自动退出
- 调用
Console.Out.Flush()强制刷新缓冲区,减少输出延迟
注意事项
- 如果应用1是UI程序(WPF/WinForms),更新UI时需要切换到UI线程(如用
Dispatcher.Invoke或Control.Invoke) - 务必在使用完
Process和CancellationTokenSource后调用Dispose(),避免内存泄漏 - 确保应用1和应用2使用相同的输出编码,防止乱码问题
内容的提问来源于stack exchange,提问作者Mdarende
相关产品推荐
相关产品推荐

