Содержание
При запуске консольного приложения операционная система автоматически связывает три потока ввода-вывода с консолью: стандартный входной поток, стандартный выходной поток и стандартный поток вывода ошибок. Приложение может считывать входные данные пользователя из стандартного входного потока, производить запись данных в стандартный выходной поток и запись данных об ошибках в стандартный поток вывода ошибок. В приложении C# эти потоки представлены в виде значений трех свойств: Console.In
, Console.Out
и Console.Error
. При необходимости, мы можем перенаправить стандартные потоки ввода-вывода и, например, сделать так, чтобы результаты каких-либо вычислений не выводились непосредственно в консоль, а записывались сразу в текстовый файл.
Перенаправление потоков ввода-вывода консоли
По умолчанию значением свойства In
является объект типа System.IO.TextReader объект
, представляющий значения, введенные с клавиатуры, а значениями свойств Out
и Error
— объекты типа System.IO.TextWriter
, представляющие окно консоли.
Чтобы перенаправить потоки стандартного ввода, стандартного вывода или стандартный поток ошибок, необходимо вызвать методы: Console.SetIn
, Console.SetOut
или Console.SetError
. Следует отметить, что методы, которые обычно асинхронны, например TextReader.ReadLineAsync
, выполняются синхронно, если объект представляет поток консоли.
Например, перенаправим поток вывода консоли (свойство Out
) в файл:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { TextWriter oldOut = Console.Out;//запоминаем предыдущее значение StreamWriter writer = new(@"output.txt");//поток вывода будем направлять в файл Console.SetOut(writer); //перенаправляем поток вывода в файл Console.WriteLine("Hello world!");//записываем в файл строку Console.SetOut(oldOut);//возвращаем предыдущее значение writer.Close();//не забываем закрыть объект и базовый поток } } }
Здесь мы перенаправили поток вывода консоли в файл output.txt
. Информацию о том, как работать с текстовыми файлами и, в частности с объектами типа StreamWriter
, можно посмотреть здесь. Теперь, если запустить приложение, то непосредственно в окно консоли ничего не будет выведено, так как поток вывода направляется в файл. При этом, рядом с exe-файлом приложения появится файл, содержащий строку "Hello world!"
. Использую оператор using
код приложения можно немного сократить:
namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { TextWriter oldOut = Console.Out;//запоминаем предыдущее значение using StreamWriter writer = new(@"output.txt");//поток вывода будем направлять в файл { Console.SetOut(writer); //перенаправляем поток вывода в файл Console.WriteLine("Hello world!");//записываем в файл строку } Console.SetOut(oldOut);//возвращаем предыдущее значение } } }
Аналогичным образом мы можем перенаправлять и поток ввода. Например, напишем следующее приложение:
internal class Program { static void Main(string[] args) { string inFile = @"input.txt"; string outFile = @"output.txt"; TextWriter oldOut = Console.Out; TextReader oldIn = Console.In; FileStream inputStream; inputStream = File.Open(inFile, FileMode.OpenOrCreate); using StreamWriter writer = new(outFile); using StreamReader reader = new(inputStream); { Console.SetOut(writer); Console.SetIn(reader); while (true) { string str = Console.ReadLine(); if (str == null) break; Console.WriteLine(str); } } Console.SetOut(oldOut); Console.SetIn(oldIn); } }
Здесь мы перенаправили поток ввода на файл input.txt
, а поток вывода — на файл output.txt
. Перед тем, как осуществить непосредственно само перенаправление потока ввода, нам необходимо убедиться, что файл из которого будут считываться данные существует, поэтому перед создание объекта типа StreamReader
мы открыли файловый поток FileStream
с флагом FileMode.OpenOrCreate
(о FileStream
и используемых флагах можно почитать здесь).
Далее мы перенаправили потоки ввода-вывода на наши файлы и в цикле while
прочитали всё содержимое из файла input.txt
и перенесли это содержимое построчно в файл output.txt
. Опять же, при таком перенаправлении потоков вода-вывода мы ничего не увидим в окне консоли, однако, приложение выполнит свою функцию — скопирует данные из одного файла в другой.
Перенаправление потока ошибок (свойство Error)
Похожим образом мы можем перенаправить стандартный поток ошибок. Для начала рассмотрим, следующий пример:
static void Main(string[] args) { TextWriter old = Console.Error; string errorFile = @"error.txt"; TextWriter error = Console.Error; using StreamWriter errors = new(errorFile); { Console.SetError(errors); int a = 0; int b = 10; int c = b / a; } Console.SetError(old); }
После запуска, это приложение будет работать также, как и до перенаправления потока ошибок в файл. То есть, ошибка деления на ноль будет выведена в консоль (хотя, рядом с exe-файлом приложения и появится файл error.txt
. Чтобы записать ошибку именно в файл, необходимо обрабатывать возможные исключения в блоках try..catch
, например, так:
static void Main(string[] args) { TextWriter old = Console.Error; string errorFile = @"error.txt"; TextWriter error = Console.Error; using StreamWriter errors = new(errorFile); { Console.SetError(errors); try { int a = 0; int b = 10; int c = b / a; } catch (Exception e) { Console.Error.WriteLine(e); } } Console.SetError(old); }
Здесь в секции catch
мы записали сведения об ошибке непосредственно в файл.
Как определить, что стандартные потоки ввода-вывода консоли были перенаправлены и вернуть стандартные значения
Чтобы определить были ли стандартные потоки ввода-вывода перенаправлены можно воспользоваться свойствами: Console.
, Console.
и Console.
. Эти свойства вернут true
, если были перенаправлены соответственно входной поток, выходной поток или поток ошибок.
В примерах выше мы запоминали значения, которые содержали свойства In
, Out
и Error
, чтобы затем вернуть эти значения обратно. Эту же операцию по возврату стандартных значений можно произвести, используя методы объекта Console
. Для получения стандартных потоков ввода-вывода консоли необходимо вызвать методы Console.OpenStandard...
Эти методы возвращают объекты типа Stream
, поэтому, чтобы вернуть обратно, например, стандартный входной поток, можно выполнить следующую операцию:
Console.SetIn(new StreamReader(Console.OpenStandardInput()));
Итого
При разработке консольных приложений не всегда требуется, чтобы пользователь вводил данные непосредственно с клавиатуры или видел результат каких-либо вычислений на экране. Для перенаправления потоков ввода-вывода консоли можно использовать методы SetIn
, SetOut
и SetError
, которые перенаправят, соответственно, входной, выходной или поток ошибок, например, в файл.