Полное руководство. С# 4.0
Шрифт:
Главное преимущество метода 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("Нажата
Вот, например, к какому результату может привести выполнение этой программы. Введите несколько символов, а по окончании - <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 Открывает существующий файл, но сокращает его длину до нуля
Если попытка открыть файл оказывается неудачной, то генерируется исклю чение. Если же файл нельзя открыть из-за того что он не существует, генерируется исключение FileNotFoundException. А если файл нельзя открыть из-за какой- нибудь ошибки ввода-вывода, то генерируется исключение IOException. К чис лу других исключений, которые могут быть сгенерированы при открытии фай ла, относятся следующие: ArgumentNullException (указано пустое имя файла), ArgumentException (указано неверное имя файла), ArgumentOutOfRangeException (указан неверный режим), SeaurityException (у пользователя нет прав доступа к файлу), PathTooLongException (слишком длинное имя файла или путь к нему), NotSupportedException (в имени файла указано устройство, которое не поддержи вается), а также DirectoryNotFoundException (указан неверный каталог).
Исключения PathTooLongException, DirectoryNotFoundException и FileNotFoundException относятся к подклассам класса исключений IOException. Поэтому все они могут быть перехвачены, если перехватывается исключение IOException.
Ниже в качестве примера приведен один из способов открытия файла test.dat для ввода. FileStream fin; try { fin = new FileStream("test", FileMode.Open); } catch(IOException exc) { // перехватить все исключения, связанные с вводом-выводом Console.WriteLine(exc.Message); // Обработать ошибку. } catch(Exception exc { // перехватить любое другое исключение. Console.WriteLine(exc.Message); // Обработать ошибку, если это возможно. // Еще раз сгенерировать необрабатываемые исключения. }