C # Асинхронное чтение данных из перенаправленного StandardOutput - PullRequest
0 голосов
/ 09 мая 2019

Я разрабатываю C # WFA, который позволяет мне делать некоторые вещи с помощью программного обеспечения для химии: GAMESS.По сути, у меня есть командный файл, который при выполнении с соответствующими аргументами возвращает файл с данными, необходимыми для атомарного анализа.

В форме приложения я установил текстовое поле только для чтения с выводом процесса.Я сделал это, изменив стандартный вывод.Это чтение выполняется синхронно.Работает хорошо для небольших выходов, но много раз, когда линии weeldes 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 ()?

1 Ответ

2 голосов
/ 10 мая 2019

Понял. Здесь следует код, который работает. Таким образом, текстовое поле будет обновляться построчно, и тупик больше не возникает.

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);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...