• Программинг

Нужны источники бесперебойного питания?

Источники бесперебойного питания от дизельстор

Консольный вывод. Читаем посимвольно.

Ранее в статье Читаем стандартный вывод консольного приложения + DOS to UTF я писал как подключаться и читать стандартный вывод консольных приложений. Все это конечно работает хорошо, но есть один нюанс – событие на которое мы подписываемся (pr.OutputDataReceived += new DataReceivedEventHandler(sortOutputHandler)) возникает только тогда, когда в консольной программе происходит переход на новую строку. В этот момент нам возвращается весь буфер строки. А так, как в одной строке можно вывести кучу информации используя, например, служебный символ \b (backspace), то для чтения текста из консоли код из предыдущей статьи может и не подойти.

На помощь приходит следующее решение. Мы создаем свой поток и подключаем к нему стандартный вывод консоли. Далее мы просто читаем наш поток и разбираем его.

В следующем коде используются переменные:
sr – наш поток, с которым мы работаем.
nsize – количество символов, которые будут читаться за раз.
buffer – массив в котором будут храниться кода символов. Сюда входят и служебные символы – переход на другую строку, backspace, tab и т.д.
sOut – ассинхронный вызов. В данном случае служит как заглушка.

В итоге получаем следующий код.

1 private void run(string utilityName, string arguments)
2 {
3     try
4     {
5         Stream sr; //поток из которого будем читать вывод консоли
6         int nsize = 5; //по сколько символов за раз будем читать. Можно установить и больше, и меньше
7         Byte[] buffer = new Byte[nsize]; //здесь то? что будем читать - размер количество символов
8         AsyncCallback sOut = new AsyncCallback(Res); //ассинхронный вызов
9  
10         //создаем новый процесс, который будет работать с консолью
11         Process pr = new Process();
12         //задаем имя запускного файла
13         pr.StartInfo.FileName = utilityName;
14         //задаем аргументы для этого файла
15         pr.StartInfo.Arguments = arguments;
16         //отключаем использование оболочки, чтобы можно было читать данные вывода
17         pr.StartInfo.UseShellExecute = false;
18         //перенаправляем данные вовода
19         pr.StartInfo.RedirectStandardOutput = true;
20         //задаем кодировку, чтобы читать кириллические символы
21         pr.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(866);
22         //запрещаем создавать окно для запускаемой программы
23         pr.StartInfo.CreateNoWindow = true;
24         //включаем возможность определять когда происходит выход из программы, которую будем запускать
25         pr.EnableRaisingEvents = true;
26         //подписываемся на событие, когда процесс завершит работу
27         pr.Exited += new EventHandler(whenExitProcess);
28  
29         //запускаем процесс
30         pr.Start();
31  
32         sr = pr.StandardOutput.BaseStream; //перенаправляем стандартный вывод в наш поток
33         sr.BeginRead(buffer, 0, nsize, sOut, null); //начинаем читать стандартный вывод консоли
34  
35         //читаем поток, пока есть что читать
36         while (sr.Read(buffer, 0, nsize) > 0)
37         {
38             //переводим массив символов в строку через кодировку dos866
39             string sym5 = System.Text.Encoding.GetEncoding(866).GetString(buffer));
40             //далее выполняем действия с полученным текстом
41             //.....
42         }
43     }
44     catch (Exception error)
45     {
46         MessageBox.Show("Ошибка при запуске!\n" + error.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
47     }
48 }
49  
50 /// <summary>
51 /// просто заглушка
52 /// </summary>
53 /// <param name="ar"></param>
54 void Res(IAsyncResult ar)
55 {
56 }
57  
58 //завершение запущенного процесса
59 private void whenExitProcess(Object sender, EventArgs e)
60 {
61     //данные об окончании работы программы
62 }

Вот что у нас получилось. Как видите читать можно хоть по 20 символов, задавая размер буфера. Задавайте вопросы, будем разбирать что не понятно.