Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#从重定向的标准输出异步读取数据_C#_Asynchronous_Redirectstandardoutput - Fatal编程技术网

C#从重定向的标准输出异步读取数据

C#从重定向的标准输出异步读取数据,c#,asynchronous,redirectstandardoutput,C#,Asynchronous,Redirectstandardoutput,我正在开发一个C#WFA,它允许我用一个化学软件做一些事情:GAMESS 基本上我有一个批处理文件,当使用适当的参数执行时,它返回一个包含原子分析所需数据的文件 在我的应用程序表单中,我设置了一个只读文本框,其中包含进程的输出。我通过重定向标准输出来实现这一点。此读取以同步方式完成。对于小输出,效果很好,但很多时候,线weel超过240k。我的进程在结束时自动关闭(最后一条指令是“退出”,而不是“退出/B”) 正如您(可能)发现的那样,主窗体变得不稳定,在进程结束之前不允许任何用户输入。这是一个

我正在开发一个C#WFA,它允许我用一个化学软件做一些事情:GAMESS

基本上我有一个批处理文件,当使用适当的参数执行时,它返回一个包含原子分析所需数据的文件

在我的应用程序表单中,我设置了一个只读文本框,其中包含进程的输出。我通过重定向标准输出来实现这一点。此读取以同步方式完成。对于小输出,效果很好,但很多时候,线weel超过240k。我的进程在结束时自动关闭(最后一条指令是“退出”,而不是“退出/B”)

正如您(可能)发现的那样,主窗体变得不稳定,在进程结束之前不允许任何用户输入。这是一个问题

我曾尝试在代码中为不同的函数异步读取文件流,效果很好,但我一直坚持标准输出。我想不出正确的方法

以下是我迄今为止的代码:

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);
}
理想情况下,以异步方式读取重定向的standardoutput可以解决我的应用程序的死锁(对吗?),或者至少可以缩短死锁的持续时间。也许如果我使用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);
    }

明白了。下面是有效的代码。这样,文本框将逐行更新,死区不再出现

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);
    }

你处理的文件有多大,真的有那么大以至于导致死锁吗?如果是这样的话,我会认为复制完整文件并删除它会带来很多麻烦,因为您没有进行异步操作。还有,你在用这个文件做什么?你需要整件东西还是一行一行地使用。我甚至没有看到你在使用文件的结果,你在用它做什么?实际上,我需要的是一种方法,来获取终端在执行这个bat文件时显示的文本。所有与文件生成和内容相关的事情都是由bat文件本身内部的代码处理的。终端输出的长度不在我的直接控制之下。这是因为根据特定的分子模型文件iI给出的脚本,输出可能会有所不同。有时是140行打印在终端上,而另一些时候是100k+行。我不知道你在用文件做什么,异步在执行非cpu密集型操作(例如网络请求/IO等)时释放线程。你说“文本框将更新得更频繁,因此更”令人愉快“。您这样说是什么意思?是否正在更新文件中每行的文本框?或者您需要更新渲染(例如gui被锁定的时间)吗?我认为您想要的是仍然使用ReadAsync,但是您想要创建一个较小的缓冲区大小,这样您就不会一次读取整个文件。e、 g创建for循环并读入块,而不是执行
0,(int)SourceStream.Length
您执行的
lastBuffer,bufferSize
您处理的文件有多大,它真的有那么大导致死锁吗?如果是这样的话,我会认为复制完整文件并删除它会带来很多麻烦,因为您没有进行异步操作。还有,你在用这个文件做什么?你需要整件东西还是一行一行地使用。我甚至没有看到你在使用文件的结果,你在用它做什么?实际上,我需要的是一种方法,来获取终端在执行这个bat文件时显示的文本。所有与文件生成和内容相关的事情都是由bat文件本身内部的代码处理的。终端输出的长度不在我的直接控制之下。这是因为根据特定的分子模型文件iI给出的脚本,输出可能会有所不同。有时是140行打印在终端上,而另一些时候是100k+行。我不知道你在用文件做什么,异步在执行非cpu密集型操作(例如网络请求/IO等)时释放线程。你说“文本框将更新得更频繁,因此更”令人愉快“。您这样说是什么意思?是否正在更新文件中每行的文本框?或者您需要更新渲染(例如gui被锁定的时间)吗?我认为您想要的是仍然使用ReadAsync,但是您想要创建一个较小的缓冲区大小,这样您就不会一次读取整个文件。e、 g创建for循环并读入块,而不是执行
0,(int)SourceStream.Length
您执行的
lastBuffer,bufferSize
我添加了以下内容以防止出现这种情况:
button1.Enabled=false然后是它所遵循的执行部分
button1.Enabled=true我添加了以下内容以防止出现这种情况:
button1.Enabled=false然后是它所遵循的执行部分
button1.Enabled=true