Книга: C# 4.0: полное руководство
Консольный ввод-вывод
Разделы на этой странице:
Консольный ввод-вывод
Консольный ввод-вывод осуществляется с помощью стандартных потоков, представленных свойствами 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()
Метод Read()
возвращает очередной символ, считанный с консоли. Он ожидает до тех пор, пока пользователь не нажмет клавишу, а затем возвращает результат. Возвращаемый символ относится к типу int
и поэтому должен быть приведен к типу char
. Если при вводе возникает ошибка, то метод Read()
возвращает значение -1. Этот метод сгенерирует исключение IOException
при неудачном исходе операции ввода. Ввод с консоли с помощью метода Read()
буферизуется построчно, поэтому пользователь должен нажать клавишу <Enter>, прежде чем программа получит любой символ, введенный с консоли.
Ниже приведен пример программы, в которой метод Read()
используется для считывания символа, введенного с клавиатуры.
// Считать символ, введенный с клавиатуры.
using System;
class KbIn {
static void Main() {
char ch;
Console.Write("Нажмите клавишу, а затем — <ENTER>: ");
ch = (char) Console.Read(); // получить значение типа char
Console.WriteLine("Вы нажали клавишу: " + ch) ;
}
}
Вот, например, к какому результату может привести выполнение этой программы.
Нажмите клавишу, а затем — <ENTER>: t
Вы нажали клавишу: t
Необходимость буферизировать построчно ввод, осуществляемый с консоли посредством метода Read()
, иногда может быть досадным препятствием. Ведь при нажатии клавиши <Enter> в поток ввода передается последовательность символов перевода каретки и перевода строки. Более того, эти символы остаются во входном буфере до тех пор, пока они не будут считаны. Следовательно, в некоторых приложениях приходится удалять эти символы (путем их считывания), прежде чем приступать к следующей операции ввода. Впрочем, для чтения введенных с клавиатуры символов без построчной буферизации, можно воспользоваться рассматриваемым далее методом ReadKey()
. Для считывания строки символов служит приведенный ниже метод ReadLine()
.
static string ReadLine()
Символы считываются методом ReadLine()
до тех пор, пока пользователь не нажмет клавишу <Enter>, а затем этот метод возвращает введенные символы в виде объекта типа string
. Кроме того, он сгенерирует исключение IOException
при неудачном исходе операции ввода.
Ниже приведен пример программы, в которой демонстрируется чтение строки из потока Console.In
с помощью метода ReadLine()
.
// Ввод с консоли с помощью метода ReadLine().
using System;
class ReadString {
static void Main() {
string str;
Console.WriteLine("Введите несколько символов.");
str = Console.ReadLine();
Console.WriteLine("Вы ввели: " + str);
}
}
Выполнение этой программы может привести, например, к следующему результату.
Введите несколько символов.
Это просто тест.
Вы ввели: Это просто тест.
Итак, для чтения данных из потока Console.In
проще всего воспользоваться методами класса Console
. Но для этой цели можно обратиться и к методам базового класса TextReader
. В качестве примера ниже приведен переделанный вариант предыдущего примера программы, в котором используется метод ReadLine()
, определенный в классе TextReader
.
// Прочитать введенную с клавиатуры строку
// непосредственно из потока Console.In.
using System;
class ReadChars2 {
static void Main() {
string str;
Console.WriteLine("Введите несколько символов.");
str = Console.In.ReadLine(); // вызвать метод ReadLine()
// класса TextReader
Console.WriteLine("Вы ввели: " + str);
}
}
Обратите внимание на то, что метод ReadLine()
теперь вызывается непосредственно для потока Console.In
. Поэтому если требуется доступ к методам, определенным в классе TextReader
, который является базовым для потока Console.In
, то подобные методы вызываются так, как было показано в приведенном выше примере.
Применение метода ReadKey()
В состав среды .NET Framework включен метод, определяемый в классе Console
и позволяющий непосредственно считывать отдельно введенные с клавиатуры символы без построчной буферизации. Этот метод называется ReadKey()
. При нажатии клавиши метод ReadKey()
немедленно возвращает введенный с клавиатуры символ. И в этом случае пользователю уже не нужно нажимать дополнительно клавишу <Enter>. Таким образом, метод ReadKey()
позволяет считывать и обрабатывать ввод с клавиатуры в реальном масштабе времени.
Ниже приведены две формы объявления метода ReadKey()
.
static ConsoleKeylnfo ReadKey()
static ConsoleKeylnfo ReadKey(bool intercept)
В первой форме данного метода ожидается нажатие клавиши. Когда оно происходит, метод возвращает введенный с клавиатуры символ и выводит его на экран. Во второй форме также ожидается нажатие клавиши, и затем возвращается введенный с клавиатуры символ. Но если значение параметра intercept
равно true
, то введенный символ не отображается. А если значение параметра intercept равно false
, то введенный символ отображается.
Метод ReadKey()
возвращает информацию о нажатии клавиши в объекте типа ConsoleKeylnfo
, который представляет собой структуру, состоящую из приведенных ниже свойств, доступных только для чтения.
char KeyChar
ConsoleKey Key
ConsoleModifiers Modifiers
Свойство KeyChar
содержит эквивалент char
введенного с клавиатуры символа, свойство Key
— значение из перечисления ConsoleKey
всех клавиш на клавиатуре, а свойство Modifiers
— описание одной из модифицирующих клавиш (<Alt>, <Ctrl> или <Shift>), которые были нажаты, если это действительно имело место, при формировании ввода с клавиатуры. Эти модифицирующие клавиши представлены в перечислении ConsoleModifiers
следующими значениями: Control, Shift
и Alt
. В свойстве Modifiers
может присутствовать несколько значений нажатых модифицирующих клавиш.
Главное преимущество метода ReadKey()
заключается в том, что он предоставляет средства для организации ввода с клавиатуры в диалоговом режиме, поскольку этот ввод не буферизуется построчно. Для того чтобы продемонстрировать данный метод в действии, ниже приведен соответствующий пример программы.
// Считать символы, введенные с консоли, используя метод ReadKey().
using System;
class ReadKeys {
static void Main() {
ConsoleKeyInfo keypress;
Console.WriteLine("Введите несколько символов, " +
"а по окончании - <Q>.");
do {
keypress = Console.ReadKey(); // считать данные о нажатых клавишах
Console.WriteLine(" Вы нажали клавишу: " + keypress.KeyChar);
// Проверить нажатие модифицирующих клавиш.
if((ConsoleModifiers.Alt & keypress.Modifiers) != 0)
Console.WriteLine("Нажата клавиша <Alt>.");
if((ConsoleModifiers.Control & keypress.Modifiers) != 0)
Console.WriteLine("Нажата клавиша <Control>.");
if((ConsoleModifiers.Shift & keypress.Modifiers) != 0)
Console.WriteLine("Нажата клавиша <Shift>.");
} while(keypress.KeyChar != 'Q');
}
}
Вот, например, к какому результату может привести выполнение этой программы.
Введите несколько символов, а по окончании - <Q>.
а Вы нажали клавишу: а
b Вы нажали клавишу: b
d Вы нажали клавишу: d
А Вы нажали клавишу: А
Нажата клавиша <Shift>.
В Вы нажали клавишу: В
Нажата клавиша <Shift>.
С Вы нажали клавишу: С
Нажата клавиша <Shift>.
• Вы нажали клавишу: •
Нажата клавиша <Control>.
Q Вы нажали клавишу: Q
Нажата клавиша <Shift>.
Как следует из приведенного выше результата, всякий раз, когда нажимается клавиша, метод ReadKey()
немедленно возвращает введенный с клавиатуры символ. Этим он отличается от упоминавшегося ранее метода Read()
, в котором ввод выполняется с построчной буферизацией. Поэтому если требуется добиться в программе реакции на ввод с клавиатуры, то рекомендуется выбрать метод ReadKey()
.
Запись данных в поток вывода на консоль
Потоки Console.Out
и Console.Error
являются объектами типа TextWriter
. Вывод на консоль проще всего осуществить с помощью методов Write()
и WriteLine()
, с которыми вы уже знакомы. Существуют варианты этих методов для вывода данных каждого из встроенных типов. В классе Console определяются его собственные варианты метода Write()
и WriteLine()
, и поэтому они могут вызываться непосредственно для класса Console, как это было уже не раз показано на страницах данной книги. Но при желании эти и другие методы могут быть вызваны и для класса TextWriter, который является базовым для потоков Console.Out
и Console.Err
or.
Ниже приведен пример программы, в котором демонстрируется вывод в потоки Console.Out
и Console.Error
. По умолчанию данные в обоих случаях выводятся на консоль.
// Организовать вывод в потоки Console.Out и Console.Error.
using System;
class ErrOut {
static void Main() {
int a=10, b=0;
int result;
Console.Out.WriteLine("Деление на нуль приведет " +
"к исключительной ситуации.");
try {
result = a / b; // сгенерировать исключение при попытке деления на нуль
} catch(DivideByZeroException exc) {
Console.Error.WriteLine(exc.Message);
}
}
}
При выполнении этой программы получается следующий результат.
Деление на нуль приведет к исключительной ситуации.
Попытка деления на нуль.
Начинающие программисты порой испытывают затруднения при использовании потока Console.Error
. Перед ними невольно встает вопрос: если оба потока, Console.Out
и Console.Error
, по умолчанию выводят результат на консоль, то зачем нужны два разных потока вывода? Ответ на этот вопрос заключается в том, что стандартные потоки могут быть переадресованы на другие устройства. Так, поток Console.Error
можно переадресовать в выходной файл на диске, а не на экран. Это, например, означает, что сорбщения об ошибках могут быть направлены в файл журнала регистрации, не мешая выводу на консоль. И наоборот, если вывод на консоль переадресуется, а вывод сообщений об ошибках остается прежним, то на консоли появятся сообщения об ошибках, а не выводимые на нее данные. Мы еще вернемся к вопросу переадресации после рассмотрения файлового ввода-вывода.
- Организация системы ввода-вывода в C# на потоках
- Классы потоков
- Консольный ввод-вывод
- Класс FileStream и байтовый ввод-вывод в файл
- Символьный ввод-вывод в файл
- Переадресация стандартных потоков
- Демонстрирование двоичного ввода-вывода
- Файлы с произвольным доступом
- Применение класса MemoryStream
- Применение классов StringReader и StringWriter
- Класс File
- Преобразование числовых строк в их внутреннее представление
- 4.4. Ввод и вывод
- Стандартные устройства и консольный ввод
- ГЛАВА 5 ВВОД И ВЫВОД
- ГЛАВА 14 Применение средств ввода-вывода
- ГЛАВА 2 Использование файловой системы и функций символьного ввода
- Включение и отключение синхронного вывода
- 2. Правила вывода Армстронга
- 3. Производные правила вывода
- 1.6 Драйверы и буферы ввода-вывода
- 1.8 Ввод-вывод типичного приложения хранения данных
- Глава 6 BIOS – базовая система ввода-вывода
- 5.2.2.2. Устройства ввода информации в персональный компьютер