Для создания символьного потока достаточно заключить байтовый поток в один из классов-оболочек символьных потоков. На вершине иерархии классов символьных потоков находятся абстрактные классы TextReader
и TextWriter
. Так, класс TextReader
организует ввод, а класс TextWriter
— вывод. Методы, определенные в обоих этих классах, доступны для всех их подклассов. Они образуют минимальный набор функций ввода-вывода, которыми должны обладать все символьные потоки.
В табл. 14.3 перечислены методы ввода, определенные в классе TextReader
. В целом, эти методы способны генерировать исключение IOException
при появлении ошибки ввода, а некоторые из них — исключения других типов. Особый интерес вызывает метод ReadLine()
, предназначенный для ввода целой текстовой строки, возвращая ее в виде объекта типа string
. Этот метод удобен для чтения входных данных, содержащих пробелы. В классе TextReader
имеется также метод Close()
, определяемый следующим образом.
void Close()
Этот метод закрывает считывающий поток и освобождает его ресурсы.
Таблица 14.3. Методы ввода, определенные в классе TextReader
В классе TextWriter
определены также варианты методов Write()
и WriteLine()
, предназначенные для вывода данных всех встроенных типов. Ниже в качестве примера перечислены лишь некоторые из перегружаемых вариантов этих методов.
Все эти методы генерируют исключение IOException
при появлении ошибки вывода.
Кроме того в классе TextWriter
определены методы Close()
и Flush()
, приведенные ниже.
virtual void Close()
virtual void Flush()
Метод Flush()
организует вывод в физическую среду всех данных, оставшихся в выходном буфере. А метод Close()
закрывает записывающий поток и освобождает его ресурсы.
Классы TextReader
и TextWriter
реализуются несколькими классами символьных потоков, включая и те, что перечислены ниже. Следовательно, в этих классах потоков предоставляются методы и свойства, определенные в классах TextReader
и TextWriter
.
Помимо классов байтовых и символьных потоков, имеются еще два класса двоичных потоков, которые могут служить для непосредственного ввода и вывода двоичных данных — BinaryReader
и BinaryWriter
. Подробнее о них речь пойдет далее в этой главе, когда дойдет черед до файлового ввода-вывода.
А теперь, когда представлена общая структура системы ввода-вывода в С#, отведем оставшуюся часть этой главы более подробному рассмотрению различных частей данной системы, начиная с консольного ввода-вывода.
Консольный ввод-вывод
Консольный ввод-вывод осуществляется с помощью стандартных потоков, представленных свойствами Console.In, Console.Out
и Console.Error
. Примеры консольного ввода-вывода были представлены еще в главе 2, поэтому он должен быть вам уже знаком. Как будет показано ниже, он обладает и рядом других дополнительных возможностей.
Но прежде следует еще раз подчеркнуть, что большинство реальных приложений C# ориентированы не на консольный ввод-вывод в текстовом виде, а на графический оконный интерфейс для взаимодействия с пользователем, или же они представляют собой программный код, используемый на стороне сервера. Поэтому часть системы ввода-вывода, связанная с консолью, не находит широкого практического применения. И хотя программы, ориентированные на текстовый ввод-вывод, отлично подходят в качестве учебных примеров, коротких сервисных программ или определенного рода программных компонентов, для большинства реальных приложений они не годятся.
Поток Console.In
является экземпляром объекта класса TextReader
, и поэтому для доступа к нему могут быть использованы методы и свойства, определенные в классе TextReader
. Но для этой цели чаще все же используются методы, предоставляемые классом Console
, в котором автоматически организуется чтение данных из потока Console.In
. В классе Console
определены три метода ввода. Два первых метода, Read()
и ReadLine()
, были доступны еще в версии .NET Framework 1.0. А третий метод, ReadKey()
, был добавлен в версию 2.0 этой среды.
Для чтения одного символа служит приведенный ниже метод Read()
.
static int Read()