|
Программирование >> Разработка устойчивых систем
Вместо ios base::failbit для краткости обычно используется запись ios::failbit. Обработка потоковых ошибок Как уже отмечалось, оператор чтения данных типа Date в некоторых ситуациях устанавливает флаг ошибочного состояния потока. Как пользователь узнает о таких ошибках? Либо вызывая специальные потоковые функции класса, либо (если его не интересует конкретный тип ошибки) просто проверяя поток в логическом контексте. Оба способа зависят от состояния флагов ошибочного состояния потока. Состояние потока в классе ios base, производным от которого является ios\ определены четыре флага для проверки состояния потока. badbit Фатальная (возможно, физическая) ошибка. Поток непригоден для дальнейшего использования. eofbit Конец входных данных (физическое завершение файлового потока или завершение консольного потока пользовательским вводом, например нажатием клавиш Ctrl+Z или Ctrl+D). failbit Операция ввода-вывода завершилась неудачей, вероятнее всего, из-за недопустимых данных (например, обнаружены буквы при чтении числа). Поток остается пригодным к использованию. Флаг failbit также устанавливается при обнаружении конца ввода. goodbU Все нормально, ошибок нет. Конец входных данных еще не обнаружен. Вы всегда можете узнать о наступлении любого из этих условий при помощи функций потоковых классов; функция возвращает логический признак установки соответствующего флага. Функция good() потокового класса возвращает true, если не установлен ни один из трех флагов аномальных состояний. Функция eof() возвращает true при установленном флаге eofbit, что происходит при попытке чтения из потока без данных (обычно из файла). Поскольку конец ввода в С++ обнаруживается по преждевременному исчерпанию данных, также устанавливается флаг failbit - признак того, что ожидаемые данные не были успешно прочитаны. Функция fail() возвращает true при установке флага failbit ши badbit, а bad() возвращает true только при установленном флаге badbit. После установки флаги аномальных состояний потока остаются активными, что иногда оказывается нежелательным. Допустим, при чтении файла до обнаружения конца файла вы хотите вернуться к более ранней позиции. Простое перемещение указателя не приводит к автоматическому сбросу флагов eofbit и failbit. Флаги приходится сбрасывать вручную с помощью функции с1еаг(): myStream.clearO: Сбрасывает все биты аномальных состояний Если после с1еаг() немедленно вызвать функцию good(), она вернет true. Как было показано при описании оператора чтения Date, функция setstate() устанавли- Обычно вместо operator bool() используется operator void*(), потому что неявные преобразования bool в int могут приводить к неожиданностям, если поток задействован в контексте, допускающем преобразование к целому типу. Операторная функция operator void*() неявно вызывается только в логических выражениях. вает заданные флаги. На другие флаги ее вызов не влияет - ранее установленные флаги остаются установленными. Чтобы установить некоторые флаги с одновременным сбросом всех остальных, воспользуйтесь перегруженной версией с1еаг(), получающей логическое выражение с указанием устанавливаемых битов: myStream.clearCios::failbit ios::eofbit): Как правило, проверка отдельных флагов аномального состояния потока выполняется относительно редко. Чаще пользователь просто желает убедиться в том, что все идет нормально. Например, читая файл от начала до конца, вы просто хотите узнать о достижении конца файла. В таких случаях можно воспользоваться функцией преобразования для типа void*, которая автоматически вызывается при включении объекта потока в логическое выражение. Чтение до конца входных данных в этой идиоме выполняется так: int i: while(myStream i) cout i endl: Помните, что функция operator () возвращает ссылку на поток, переданный в аргументе, поэтому условие while проверяет объект потока в логическом выражении. Этот конкретный пример предполагает, что входной поток myStream содержит целые числа, разделенные пропусками. Функция ios base::operator void*() просто вызывает good() для своего потока и возвращает результат. Поскольку большинство потоковых операций возвращает свои потоки, эта идиома часто применяется на практике. Потоки ввода-вывода и исключения Потоки ввода-вывода появились в С++ гораздо раньше исключений, поэтому в прежние времена состояние потока проверялось только вручную , то есть вызовом проверочных функций. Для сохранения совместимости именно эта возможность считается основной, но современные реализации потоков ввода-вывода могут сообщать об ошибках при помощи исключений. Функции класса потока exceptions() передается параметр, определяющий флаги состояния, для которых должно запускаться исключение. При каждом переходе в такое состояние поток запускает исключение типа std::ios base::failure, производное от std::exception. Хотя исключения могут генерироваться для всех четырех состоянри ! потоков, разрешать все четыре исключения не всегда разумно. Как объяснялось в главе 1, исключения следует применять в действительно исключительных состояниях, однако состояние конца файла не только не является исключительным - его появление ожидается] По этой причине исключения обычно разрешаются только для ошибок, представленных флагом bad bit: myStream.exceptions(ios::badbit): Запуск исключений разрешается для каждого потока по отдельности, так как функция exceptions() является функцией потоковых классов. Функция exceptions() bas i c i St ream<cha гТ> bas1 c ost reariKcha гТ> basic 1ostream<charT> basic 1fsream<charT> basic ofstream<charT> basic fstream<charT> Как и прежде, фактически используемые классы представляют собой специализации шаблонов для определенных типов. Например, класс ifstream, предназначенный для обработки файлов char, определяется следующим образом: typedef bas1c 1fstream<char> Ifstream; Целочисленный тип, предназначенный для хранения набора битовых флагов. возвращает битовую маску (lostate - некоторого типа, преобразуемого к int; конкретный выбор зависит от компилятора), указывающую, какие состояния потоков будут порождать исключения. Если соответствующие флаги уже были установлены, исключение запускается немедленно. Конечно, чтобы использовать исключения с потоками, нужно подготовиться к их перехвату. Отсюда следует, что все операции с потоками должны выполняться внутри блока try с обработчиком ios::fai4ure. Многие программисты считают, что это неудобно, и вручную проверяют состояние потока там, где предполагаются ощибки (в частности, предполагается, что функция bad О крайне редко возвращает true). Это другая причина, по которой механизм обработки исключений считается дополнительным, а не основным средством передачи информации об ошибках. Так или иначе, вы сами выбираете более удобный способ. По тем же причинам, по которым мы рекомендуем применять исключения для обработки ошибок в других контекстах, мы будем использовать их здесь. Файловые потоки ввода-вывода Работать с файлами при помощи потоков ввода-вывода гораздо проще и безопаснее, чем с применением библиотеки stdio языка С. Чтобы открыть файл, достаточно создать в программе объект - конструктор берет на себя всю работу. Закрывать файлы необязательно (хотя это можно сделать вызовом функции close()), поскольку деструктор автоматически закроет файл при выходе объекта из области видимости. Чтобы создать объект файла, по умолчанию предназначенного для чтения данных, создайте объект ifstream; объект файла для записи представляется объектом ofstream. Объекты fstream позволяют выполнять как чтение, так и запись. Место классов файловых потоков в общей иерархии ввода-вывода показано на следующем рисунке:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |