Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/47: Рейтинг темы: голосов - 47, средняя оценка - 4.85
29 / 1 / 0
Регистрация: 14.12.2013
Сообщений: 7

Перенаправление ввода/вывода при запуске процессов

14.12.2013, 14:51. Показов 9895. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Все это для Windows 8 для одного языка, VS2010 Pro (русские), на других не пробовал.

Проблема в том, что вопросы к пользователю не выводятся сразу или выводятся не полностью.
Например для XCOPY, если указать копирование существующего файла в несуществующий каталог, то должен выводиться вопрос (для русской ОС):

Что означает указанное_имя_пути:
имя файла или каталога
(F = файл, D = каталог)?


Но у меня выводится только:

Что означает указанное_имя_пути:
имя файла или каталога


Как это победить??? Чтобы выводилось сразу и полностью.
Уже не помню как, но были случаи, что вообще ничего не отображалось (хотя ввод/вывод перенаправлялся). XCOPY висит ожидая ввода от пользователя, но ничего не пишет. Только если ввести что нибудь, то выводится вопрос, причем с ответом.


Исходный код
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
 
namespace nx_xcopy
{
    class Program
    {
        static void Main(string[] args)
        {
            ProcessConsole process = new ProcessConsole("xcopy", "\"C:\\test\\src\\file.txt\" \"C:\\test\\dst5\" /F");
            process.Start();
            process.WaitForExit();
        }
    }
 
 
    public class ProcessConsole
    {
        public ProcessConsole(string fileName, string arguments)
        {
            _fileName = fileName;
            _arguments = arguments;
        }
 
        public virtual void Start()
        {
            ProcessStartInfo startInfo = new ProcessStartInfo(_fileName, _arguments);
            startInfo.CreateNoWindow = true;
            startInfo.UseShellExecute = false;
            startInfo.RedirectStandardError = true;
            startInfo.RedirectStandardOutput = true;
            startInfo.RedirectStandardInput = true;
            _process = new Process();
            _process.StartInfo = startInfo;
            _process.OutputDataReceived += new DataReceivedEventHandler(OutputDataReceivedEventHandler);
            _process.ErrorDataReceived += new DataReceivedEventHandler(ErrorDataReceivedEventHandler);
            _process.Start();
            _process.BeginOutputReadLine();
            _process.BeginErrorReadLine();
            _input = _process.StandardInput;
            Thread thread = new Thread(InputThread);
            thread.IsBackground = true;
            thread.Start();
        }
 
        public virtual void WaitForExit()
        {
            _process.WaitForExit();
        }
 
        public virtual int ExitCode
        {
            get
            {
                return _process.ExitCode;
            }
        }
 
        protected virtual void InputThread()
        {
 
            ConsoleKeyInfo keyInfo;
            while (true)
            {
                _input.Flush();
                keyInfo = Console.ReadKey(true);
                _input.Write(keyInfo.KeyChar);
                Console.WriteLine("Input :" + keyInfo.KeyChar); 
            }
        }
 
        protected virtual void OutputDataReceivedEventHandler(Object sender, DataReceivedEventArgs e)
        {
            if (String.IsNullOrEmpty(e.Data) == false)
            {
                _output = e.Data;
                Console.WriteLine("Output : " + _output);
            }
        }
 
        protected virtual void ErrorDataReceivedEventHandler(Object sender, DataReceivedEventArgs e)
        {
            if (String.IsNullOrEmpty(e.Data) == false)
            {
                _error = (e.Data + Environment.NewLine);
                Console.WriteLine("Error : " + _error);
            }
        }
 
        string _fileName;
        string _arguments;
        private Process _process;
        private string _output;
        private string _error;
        StreamWriter _input;
    }
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
14.12.2013, 14:51
Ответы с готовыми решениями:

Перенаправление вывода с консоли
Здравствуйте! Пытаюсь вот разобраться с перенаправлением вывода с консоли... А точнее, хочу написать "оболочку" для стороннего...

Перенаправление вывода с консоли в RichTextBox
Читающему доброе время суток. Когда то пришлось столкнуться с консолью, теперь столкнулся с такой задачей как перенаправляемый вывод с...

Перенаправление вывода с консоли в richTextBox
Здравствуйте, столкнулся с проблемой. Нужно, чтобы вывод с консоли перенаправлялся в richTextBox, но, чтобы это происходило мгновенно, а не...

14
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
14.12.2013, 17:18
wtd, наверняка это системные изменения в ядре, на которые не повлиять. Вопроса два
1) зачем такие сложности?
2) пробовали ли вместо cmd использовать powershell? там должно быть полегче, он и задумывался как замена cmd. В ближайшее время cmd думаю вообще пропадет, начиная с 8.2 - 9.
0
29 / 1 / 0
Регистрация: 14.12.2013
Сообщений: 7
14.12.2013, 18:09  [ТС]
Не думаю, что cmd.exe уберут. Но суть не в этом. Я так понимаю, cmd или powershell - нет разницы, вызовы WinAPI из xcopy или чего-то еще там все-равно будут те же. Видимо что-то не так я делаю. Это теоретический вопрос, споткнулся, хочется разобраться.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
14.12.2013, 19:20
ЛУчше так писать:
C#
1
 ProcessConsole process = new ProcessConsole("xcopy", @"C:\test.txt C:\test\dst5 /F");
проблема воспроизводится в семерке, так что щас потыкаем ваше произведение )

Добавлено через 15 минут
Кажется разобрался, попробуйте что-нибудь написать после вывода. У меня получилось так
Output : Что означает C:\1:
Output : имя файла или каталога
Input :j
Output : (F = файл, D = каталог)? j
Output : Что означает C:\1:
Output : имя файла или каталога
видимо это какие-то костыли внутри самого microsoft

Добавлено через 2 минуты
С небольшими косметическими улучшениями:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
 
namespace nx_xcopy
{
    class Program
    {
        static void Main()
        {
            ProcessConsole process = new ProcessConsole("xcopy", @"C:\test.txt C:\1 /F");
            process.Start();
            process.WaitForExit();
        }
    }
 
 
    public class ProcessConsole
    {
        public ProcessConsole(string fileName, string arguments)
        {
            _fileName = fileName;
            _arguments = arguments;
        }
 
        public virtual void Start()
        {
            ProcessStartInfo startInfo = new ProcessStartInfo(_fileName, _arguments)
                                         {
                                             CreateNoWindow = true,
                                             UseShellExecute = false,
                                             RedirectStandardError = true,
                                             RedirectStandardOutput = true,
                                             RedirectStandardInput = true
                                         };
            _process = new Process {StartInfo = startInfo};
            _process.OutputDataReceived += OutputDataReceivedEventHandler;
            _process.ErrorDataReceived += ErrorDataReceivedEventHandler;
            _process.Start();
            _process.BeginOutputReadLine();
            _process.BeginErrorReadLine();
            _input = _process.StandardInput;
            Thread thread = new Thread(InputThread) {IsBackground = true};
            thread.Start();
        }
 
        public virtual void WaitForExit()
        {
            _process.WaitForExit();
        }
 
        public virtual int ExitCode
        {
            get
            {
                return _process.ExitCode;
            }
        }
 
        protected virtual void InputThread()
        {
 
            ConsoleKeyInfo keyInfo;
            while (true)
            {
                _input.Flush();
                keyInfo = Console.ReadKey(true);
                _input.Write(keyInfo.KeyChar);
                Console.WriteLine("Input :" + keyInfo.KeyChar);
            }
        }
 
        protected virtual void OutputDataReceivedEventHandler(Object sender, DataReceivedEventArgs e)
        {
            if (String.IsNullOrEmpty(e.Data) == false)
            {
                _output = e.Data;
                Console.WriteLine("Output : " + _output);
            }
        }
 
        protected virtual void ErrorDataReceivedEventHandler(Object sender, DataReceivedEventArgs e)
        {
            if (String.IsNullOrEmpty(e.Data) == false)
            {
                _error = (e.Data + Environment.NewLine);
                Console.WriteLine("Error : " + _error);
            }
        }
 
        readonly string _fileName;
        readonly string _arguments;
        private Process _process;
        private string _output;
        private string _error;
        StreamWriter _input;
    }
}
0
29 / 1 / 0
Регистрация: 14.12.2013
Сообщений: 7
15.12.2013, 22:33  [ТС]
Все дело в том, что в подобных случаях в конце строки нет символа перевода строки и/или возврата каретки.
Т.е. в ресурсах исходная строка хранится примерно так "Что означает %1s:\nимя файла или каталога\n(F = файл, D = каталог)? ".
Получается, WriteConsole записывает символы в буфер консоли (в конце перевод строки не выполняется, т.к. его нет), далее ожидается ввод пользователя.
А вот операция асинхронного чтения, которая запускается методом Process::BeginOutputReadLine, читает по строкам. Т.е. считывает первые две фразы, а далее ждет символы перевода строки и/или возврата каретки. И пока этих символов нет событие OutputDataReceived не генерируется...
Короче, это можно победить при помощи Process::StandardOutput::Read
примерно так
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void OutputThread()
{
    // BUFFER_SIZE = 4096;
    char[] buffer = new char[BUFFER_SIZE];
    while (true)
    {
        _output = "";
        do
        {
            int count = _process.StandardOutput.Read(buffer, 0, BUFFER_SIZE);
            _output += new string(buffer, 0, count);
        }
        while (_process.StandardOutput.Peek() != -1);
        Console.WriteLine("Output : " + _output);
    }
}
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
15.12.2013, 23:13
wtd, несовсем понятно, почему тогда он две строчки пишет, а не 1.
0
29 / 1 / 0
Регистрация: 14.12.2013
Сообщений: 7
16.12.2013, 06:47  [ТС]
По-тому, что в исходной строке три подстроки, разделенных двумя управляющими символами перевода строки:
"Что означает %1s:\nимя файла или каталога\n(F = файл, D = каталог)? "
Вот после считывания первых двух подстрок генерируется событие OutputDataReceived. А вот после (F = файл, D = каталог)? управляющего символа перевода строки НЕТ, поэтому операция асинхронного считывания не генерирует событие OutputDataReceived.
1
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
16.12.2013, 07:42
wtd, забавный косяк
0
 Аватар для ksk
624 / 495 / 43
Регистрация: 05.07.2010
Сообщений: 1,589
16.12.2013, 10:35
А если в конец командной строки добавить
C#
1
"{0}echo End{0}",Enviroment.Newline ...,
станет легче?

Добавлено через 2 часа 3 минуты
Ещё из процесса торчит стандартный поток вывода, можно ему ReadToEnd сделать, когда всё кончится и дополучить последнюю строчку.
0
29 / 1 / 0
Регистрация: 14.12.2013
Сообщений: 7
16.12.2013, 11:34  [ТС]
ksk, именно в данном и подобных случаях такое действие приведет к частично повторяющемуся выводу сообщения (если я правильно понял, не пробовал):

Что означает указанное_имя_пути:
имя файла или каталога
(F = файл, D = каталог)?
Что означает указанное_имя_пути:
имя файла или каталога



Вот как это должно примерно происходить, когда XCOPY не понимает, что такое второй аргумент:

1) Наш процесс перенаправляет StdIn, StdOut, StdErr процесса XCOPY. Содержимое буферов StdOut, StdErr возвращается нашему приложению строками и только тогда, когда строка заканчивается '\r' и/или '\n'.

2) XCOPY записывает в StdOut текстовое сообщение:
"Что означает указанное_имя_пути:\nимя файла или каталога\n(F = файл, D = каталог)? "

3) Наш процесс получает из перенаправленного StdOut только первые две части сообщения:
"Что означает указанное_имя_пути:\nимя файла или каталога\n"

4) Теперь в буфере StdOut процесса XCOPY осталось:
"(F = файл, D = каталог)? "

5) XCOPY ожидает ввод (причем это должно быть функция ReadConsole, у которой логика типа метода ReadKey в C#, без ожидания Enter после ввода).

6) Из командной строки на StdIn процесса XCOPY поступает какой-то символ, не ожидаемый логикой XCOPY (не обязательно это Enviroment.Newline). И с таким же успехом можно из нашего процесса записать в StdIn процесса XCOPY любой символ, кроме ожидаемых, результат будет практически тот же.

7) Логика XCOPY не понимает такой ответ, так как ожидает только символы F или D.

8) XCOPY записывает в StdOut:
"введенный_символ\nЧто означает указанное_имя_пути:\nимя файла или каталога\n(F = файл, D = каталог)? "
(Повтор сообщения выводится с новой строки, именно поэтому после введенного_символа, перед повтором сообщением присутствует '\n')

9) С учетом того, что оставалось и было добавлено, теперь в буфере StdOut процесса XCOPY находится следующее:
"(F = файл, D = каталог)? введенный_символ\nЧто означает указанное_имя_пути:\nимя файла или каталога\n(F = файл, D = каталог)? "

10) Соответственно, наш процесс получает из буфера StdOut процесса XCOPY все содержимое вплоть до последнего символа '\n' и включая его, но не более:
"(F = файл, D = каталог)? введенный_символ\nЧто означает указанное_имя_пути:\nимя файла или каталога\n"

11) Теперь в буфере StdOut процесса XCOPY осталось:
"(F = файл, D = каталог)? "

12) XCOPY ожидает ввод.


Вообще вопрос вроде бы уже решен. По-сути, получаем то же асинхронное чтение из буфера перенаправленных потоков StdOut и StdError процесса, но, самое главное, читаем буфер полностью, а не так как это реализовано MS.
Пример, конечно же, упрощенный. Вывод на консоль навряд ли стоит выполнять из потоков, где выполняется чтение, и этот вывод, возможно, потребуется синхронизировать. Короче, при желании можно все сделать более продвинуто, как в Process (подглядываем в Mono) .

Добавлено через 1 минуту
Цитата Сообщение от ksk Посмотреть сообщение
Ещё из процесса торчит стандартный поток вывода, можно ему ReadToEnd сделать, когда всё кончится и дополучить последнюю строчку.
Здесь асинхронное чтение из перенаправленных потоков, а ReadToEnd синхронное. Смешивать нельзя.
0
 Аватар для ksk
624 / 495 / 43
Регистрация: 05.07.2010
Сообщений: 1,589
16.12.2013, 12:56
Цитата Сообщение от wtd Посмотреть сообщение
Смешивать нельзя.
Смешивать никто и не заставляет. Насколько я понял, это разовое действие.
0
29 / 1 / 0
Регистрация: 14.12.2013
Сообщений: 7
16.12.2013, 14:33  [ТС]
Не обязательно разовое, например, опять же для XCOPY, если файлы в папке назначения существуют, то может (зависит от ключей) выводиться запрос на перезапись каждого. Но это частный случай. А вообще, мало ли насколько может быть развернут обмен сообщениями таким способом. Поэтому aсинхронное чтение перенаправленного потока хорошая задумка. Только реализована она в классе Process косячно, как выразился Psilon. Ведь получается: либо пользуйся синхронным чтением; либо перенаправленный вывод может быть прочитан не полностью. ИМХО, нафиг такую асинхронную фичу было вовсе добавлять. Вот и получается, что приходится пользоваться синхронным чтением, а асинхронность добавлять ручками.
0
 Аватар для ksk
624 / 495 / 43
Регистрация: 05.07.2010
Сообщений: 1,589
16.12.2013, 16:56
у меня в одном проекте используется асинхонный обмен через стандартный ввод-вывод с чужим приложением. По полгода без перезапуска работает и никаких траблов нет. Так что реализована эта фича не косячно, просто она немного под другое заточена.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6101 / 4957 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
16.12.2013, 16:58
ksk, умвр, ясно все...
0
 Аватар для ksk
624 / 495 / 43
Регистрация: 05.07.2010
Сообщений: 1,589
16.12.2013, 17:18
Цитата Сообщение от Psilon Посмотреть сообщение
ksk, умвр, ясно все...
и умсвр тоже, как это ни парадоксально
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
16.12.2013, 17:18
Помогаю со студенческими работами здесь

Перенаправление вывода консольного приложения в WinForm
Добрый день! Имеется программа AVRDude. Консольный вариант. Делаю перенаправление вывода с этого консольного приложения в WinForm. Все ...

Перенаправление вывода ASP в файл
Встал вопрос можно ли заставить ASP скрипт выводить свои данные не (только) клиенту, а (еще и) в файл?

Перенаправление вывода процеса
Всем привет! Я запускаю процес: Process.Start(Options.CompilerPath, Options.CompilerArgs); Это консольная программа какая всю...

Перенаправление вывода из java-приложения в c#
Здравствуйте. Есть клиент-серверное java-приложение (виртуальная файловая система). Клиент - консольное приложение, которое управляет...

Process. Перенаправление потока вывода и закрытие формы
Добрый день. Написал консольное приложение, которое имитирует какую-то работу и что-то выводит в консоль (пару слов в секунду). ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка. Рецензия / Мнение Это мой обзор планшета X220 с точки зрения школьника. Недавно я решила попытаться уменьшить свой. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru