c# - C# 从重定向的 StandardOutput 异步读取数据
问题描述
我正在开发一个 C# WFA,它允许我用一个化学软件做一些事情:GAMESS。
基本上我有一个批处理文件,当使用适当的参数执行时,它会返回一个包含原子分析所需数据的文件。
在我的应用程序表单中,我设置了一个带有进程输出的只读文本框。我通过重定向标准输出来做到这一点。此读取以同步方式完成。适用于小输出,但很多时候线条超过 240k。我的进程在结束时自动关闭(最后一条指令是“EXIT”,而不是“EXIT /B”)。
正如您(可能)发现的那样,主表单变得不稳定,并且在流程结束之前不允许任何用户输入。这是个问题...
我已经尝试在我的代码中为不同的函数异步读取 FileStream,并且工作得很好,但我对 StandardOutput 的问题感到困惑。我想不出正确的方法来做到这一点。
到目前为止,这是我的代码:
private void Button1_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(Input_job_file) && !String.IsNullOrEmpty(Log_file))
{
textBox3.Text = "Executing code...\r\n";
string outtext;
string batpath = string.Format(Settings.Default.path_to_gamess + "\\rungms.bat");
string arguments = string.Format("{0} {1} {2} 0 {3}", Input_job_file, Settings.Default.version, Ncpus, Log_file);
//Here we need to copy the input file to the gamess directory in order to avoid errors
File.Copy(Input_job_file, Settings.Default.path_to_gamess + "\\" + FileNameWithoutExtension + ".inp");
Process gamessjob = new Process();
gamessjob.StartInfo.ErrorDialog = true;
gamessjob.StartInfo.UseShellExecute = false;
gamessjob.StartInfo.CreateNoWindow = true;
gamessjob.StartInfo.RedirectStandardOutput = true;
gamessjob.StartInfo.RedirectStandardError = true;
gamessjob.EnableRaisingEvents = true;
gamessjob.StartInfo.WorkingDirectory = Settings.Default.path_to_gamess;
gamessjob.StartInfo.FileName = batpath;
gamessjob.StartInfo.Arguments = arguments; //input_file, version, number_of_processors, "0", output_name]
gamessjob.Start();
//STDOUT redirection to our textbox in readonly mode
outtext = gamessjob.StandardOutput.ReadToEnd();
textBox3.Text += outtext + "\r\nProcess executed!";
//here we clean up some stuff after GAMESS code ends
File.Delete(Settings.Default.path_to_gamess + "\\" + FileNameWithoutExtension + ".inp");
MessageBox.Show("Code executed!\nCheck output for errors or messages.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else MessageBox.Show("Input file and/or output location is invalid!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
//ASYNC
byte[] result;
textBox6.Text = "Executing code...\r\n\n";
using (FileStream SourceStream = File.Open(Input_dat_file, FileMode.Open))
{
result = new byte[SourceStream.Length];
await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length);
}
理想情况下,异步读取重定向的标准输出应该可以解决我的应用程序的死锁(对吗?),或者至少减少它的持续时间。也许如果我使用 ReadLineAsync() 而不是 ReadToEndAsync() 执行此操作,文本框将更频繁地更新,因此更“令人愉悦”。
我已经搜索了异步操作的教程,但它们都显示了基于文件的操作。寻找重定向标准输出和异步的 Microsoft 参考让我更加困惑。
有人可以帮我找出一种使用 ReadLineAsync() 逐行读取输出的方法吗?
解决方案
知道了。下面是有效的代码。这样,文本框将逐行更新,并且不再出现死块。
public async void Button1_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(Input_job_file) && !String.IsNullOrEmpty(Log_file ))
{
textBox3.Text = "Executing code...\r\n";
string outtext;
string batpath = string.Format(Settings.Default.path_to_gamess + "\\rungms.bat");
string arguments = string.Format("{0} {1} {2} 0 {3}", Input_job_file, Settings.Default.version, Ncpus, Log_file);
//Here we need to copy the input file to the gamess directory in order to avoid errors
File.Copy(Input_job_file, Settings.Default.path_to_gamess + "\\" + FileNameWithoutExtension + ".inp");
Process gamessjob = new Process();
gamessjob.StartInfo.ErrorDialog = true;
gamessjob.StartInfo.UseShellExecute = false;
gamessjob.StartInfo.CreateNoWindow = true;
gamessjob.StartInfo.RedirectStandardOutput = true;
gamessjob.StartInfo.RedirectStandardError = true;
gamessjob.EnableRaisingEvents = true;
gamessjob.StartInfo.WorkingDirectory = Settings.Default.path_to_gamess;
gamessjob.StartInfo.FileName = batpath;
gamessjob.StartInfo.Arguments = arguments; //input_file, version, number_of_processors, "0", output_name]
gamessjob.Start();
//STDOUT redirection to our textbox in readonly mode
while((outtext = await gamessjob.StandardOutput.ReadLineAsync()) != null)
{
textBox3.Text += outtext + "\r\n";
}
textBox3.Text += "\r\nProcess executed!";
//here we clean up some stuff after GAMESS code ends
File.Delete(Settings.Default.path_to_gamess + "\\" + FileNameWithoutExtension + ".inp");
MessageBox.Show("Code executed!\nCheck output for errors or messages.", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else MessageBox.Show("Input file and/or output location is invalid!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
推荐阅读
- stripe-payments - 使用新创建的帐户时出现条带错误“No such payment_intent: pi_1GS0redacted”
- java - 为什么在使用 setter 和 getter 时 void 方法中的公式在子类中不起作用?
- ios - 我可以在 ios 应用程序图标上显示星号或圆点而不是徽章计数吗?
- javascript - 如果我有来自 AWS textract 方法(StartDocumentAnalysis)的 JobId,如何找到提取的文本?
- javascript - 可以通过firebase功能访问firebase admin
- android - 带有阿拉伯语的 Android RTL 布局在小米设备中不起作用
- angular - 在使用数据源实现角度材质时,连接和断开连接,出现错误
- javascript - 如何在单击按钮时生成带有选择选项标签和一些按钮的 div?
- python - 根据列顺序对 df 进行分类
- html - 将“复选框”链接到另一个容器中的元素的任何方式(仅限 HTML/CSS)