Символы считываются методом 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. В качестве примера ниже приведен переделанный вариант предыду щего примера программы, в котором используется метод Rea.dLine(), определенный в классе 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 ConsoleKeyInfo ReadKey() static ConsoleKeyInfo ReadKey(bool intercept)
В первой форме данного метода ожидается нажатие клавиши. Когда оно проис ходит, метод возвращает введенный с клавиатуры символ и выводит его на экран. Во второй форме также ожидается нажатие клавиши, и затем возвращается введенный с клавиатуры символ. Но если значение параметра intercept равно true, то введен ный символ не отображается. А если значение параметра intercept равно false, то введенный символ отображается.
Метод ReadKey() возвращает информацию о нажатии клавиши в объекте типа ConsoleKeyInfo, который представляет собой структуру, состоящую из приведенных ниже свойств, доступных только для чтения. char KeyChar ConsoleKey Key ConsoleModifiers Modifiers
Свойство KeyChar содержит эквивалент char введенного с клавиатуры символа, свойство Key — значение из перечисления ConsoleKey всех клавиш на клавиатуре, а свойство Modifiers — описание одной из модифицирующих клавиш (, или ), которые были нажаты, если это действительно имело место, при фор мировании ввода с клавиатуры. Эти модифицирующие клавиши представлены в перечислении 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.Error.
Ниже приведен пример программы, в котором демонстрируется вывод в потоки 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 можно переадресовать в выходной файл на диске, а не на экран. Это, например, означает, что сообщения об ошибках могут быть направлены в файл журна ла регистрации, не мешая выводу на консоль. И наоборот, если вывод на консоль пере адресуется, а вывод сообщений об ошибках остается прежним, то на консоли появятся сообщения об ошибках, а не выводимые на нее данные. Мы еще вернемся к вопросу переадресации после рассмотрения файлового ввода-вывода. Класс FileStream и байтовый ввод-вывод в файл
В среде .NET Framework предусмотрены классы для организации ввода-вывода в файлы. Безусловно, это в основном файлы дискового типа. На уровне операционной системы файлы имеют байтовую организацию. И, как следовало ожидать, для ввода и вывода байтов в файлы имеются соответствующие методы. Поэтому ввод и вывод в файлы байтовыми потоками весьма распространен. Кроме того, байтовый поток вво да или вывода в файл может быть заключен в соответствующий объект символьного потока. Операции символьного ввода-вывода в файл находят применение при обра ботке текста. О символьных потоках речь пойдет далее в этой главе, а здесь рассматри вается байтовый ввод-вывод.
Для создания байтового потока, привязанного к файлу, служит класс FileStream. Этот класс является производным от класса Stream и наследует всего его функции.
Напомним, что классы потоков, в том числе и FileStream, определены в простран стве имен System.IO. Поэтому в самом начале любой использующей их программы обычно вводится следующая строка кода. using System.IO; Открытие и закрытие файла
Для формирования байтового потока, привязанного к файлу, создается объект класса FileStream. В этом классе определено несколько конструкторов. Ниже при веден едва ли не самый распространенный среди них: FileStream(string путь, FileMode режим)
где путь обозначает имя открываемого файла, включая полный путь к нему; а ре жим — порядок открытия файла. В последнем случае указывается одно из значений, определяемых в перечислении FileMode и приведенных в табл. 14.4. Как правило, этот конструктор открывает файл для доступа с целью чтения или записи. Исключе нием из этого правила служит открытие файла в режиме FileMode.Append, когда файл становится доступным только для записи.
Таблица 14.4. Значения из перечисления FileMode Значение Описание FileMode.Append Добавляет выводимые данные в конец файла FileMode.Create Создает новый выходной файл. Существующий файл с таким же именем будет разрушен FileMode.CreateNew Создает новый выходной файл. Файл с таким же именем не должен существовать FileMode.Open Открывает существующий файл FileMode.OpenOrCreate Открывает файл, если он существует. В противном случае создает новый файл FileMode.Truncate Открывает существующий файл, но сокращает его длину до нуля