|
Программирование >> Разработка устойчивых систем
Поиск в потоках ввода-вывода 147 Программа записывает стихотворение в файл, используя двоичный поток вывода. Поскольку файл открывается заново через объект ifstream, для позиционирования вызывается функция seekg(). Как видите, позиционирование может выполняться от начала, от конца файла или от текущей позиции в файле. Естественно, для позиционирования от начала файла смещение должно быть положительным, а для позиционирования от конца файла - отрицательным. Зная, что такое streambuf и как смещается текущая позиция, вы сможете разобраться в альтернативном способе создания объекта потока, обеспечивающего чтение и запись в файл (без использования fstream). Следующая программа создает объект ifstream с флагами, указывающими, что файл будет задействован для чтения и записи. Запись в ifstream невозможна, поэтому нам придется создать поток ostream с тем же потоковым буфером: ifstream inCfilename . ios::in ios::out ); ostream outCin.rdbufO): Что же произойдет при записи в один из этих объектов? Пример: : C04:Iofile.cpp Чтение и запись в файл. #include <fstream> linclude <iostream> linclude ../require.h using namespace std: int mainO { ifstream in( Iofile.cpp ): assureCin. lofile.cpp ): ofstream out( Iofile.out ): assureCout. lofile.out ): out in.rdbufO: Копирование файла in.closeO: out.closeO: Открытие для чтения и записи: ifstream in2( lofile.out , ios::in ios::out): assure(in2. lofile.out ): ostream out2(in2.rdbuf()): cout in2.rdbuf(): Вывод всего файла out2 Where does this end up? : out2.seekp(0. ios::beg): out2 And what about this? ; in2.seekg(0. ios::beg): cout in2.rdbuf(): } III:- В первых пяти строках исходный код программы копируется в файл с именем iofile.out, после чего файлы закрываются. Так мы получаем текстовый файл для безопасных экспериментов. Затем мы применяем упоминавщуюся методику для создания двух объектов, читающих и записывающих данные в один файл. В команде cout in2.rdbuf() позиция чтения инициализируется позицией начала файла. С другой стороны, позиция записи устанавливается в конец файла, чтобы строка Where does this end up? была присоединена к файлу. Если переместить позицию записи в начало файла функцией seekp(), выводимый текст будет записываться иоверх существующего текста. Чтобы наглядно продемонстрировать эффект обеих операций вывода, мы перемещаем позицию чтения в начало файла функцией seekgO и выводим содержимое файла. Файл автоматически закрывается при выходе out2 из области видимости и вызове деструктора. Строковые потоки Строковые потоки работают не с файлами и не с консолью, а непосредственно с памятью. Они используют те же функции чтения и форматирования, что и cin с cout, для работы с байтами в памяти. Имена классов строковых потоков образуются по тому же принципу, что и имена файловых потоков. Если вы хотите создать строковый поток для чтения символов, создайте объект istringstream. Если строковый поток предназначен для вывода символов, создайте объект ostringstream. Все объявления строковых потоков собраны в стандартном заголовочном файле <sstream>. Шаблоны классов образуют иерархию, изображенную на следующей диаграмме: baslc istream<charT> -5- bas1c ostream<charT> -- basic 1ostream<charT> ba s i c i s t г i ngst ream<cha гТ> basi c ost r1 ngtreatiKCha гТ> bas1c str1ngstream<charT> Строковые ПОТОКИ ввода Чтобы читать данные из строки с использованием потоковых операций, создайте объект istringstream, инициализированный строкой. Следующая программа демонстрирует работу с объектом istringstream: : С04:Istring.срр Строковые потоки ввода #1 nclude <cassert> #1 ncl ude <cmath> Для fabsO linclude <iostrean)> linclude <limits> Для eps1lon() linclude <sstream> linclude <str1ng> using namespace std: Int mainO { istringstream s( 47 1.414 This is a test ); int 1: double f; s i f: Входные данные разделяются пропусками assertCi - 47); double relerr - (fabs(f) - 1.414) / 1.414; assertCrelerr <- numeric limits<double>::epsilon()); string buf2: s buf2; 3a дополнительной информацией о допустимых отклонениях и вычислениях с плавающей запятой обращайтесь к статье ТЬе Standard С Library, Part 3 в C/C+ + Users Journal, март 1995 г., по адресу www.freshsources.com/1995006a.htm. assert(buf2 == This ): cout s.rdbufO: is a test } /:- Такой способ преобразования символьных строк в типизованные значения оказывается более гибким и универсальным, чем функции atof() и atoi() стандартной библиотеки С, хотя для одиночных преобразований последний вариант может оказаться более эффективным. В выражении s i f первое число читается в переменную i, а второе - в переменную f. Данные отбираются не по критерию первой группы символов, ограниченной пропусками , потому что все зависит от типа данных читаемой переменной. Например, для строки 1.414 47 This is а test переменной i было бы присвоено значение 1, поскольку чтение остановилось бы на десятичной точке. Далее переменной f было бы присвоено значение 0.414. Такое деление хорошо подходит для разбиения вешественного числа на целую и дробную части, но в остальных ситуациях оно больше похоже на ошибку. Второй вызов assert() вычисляет относительное расхождение между прочитанными и ожидаемыми данными; всегда лучше использовать этот способ вместо прямого сравнения вещественных чисел. Константа, возвращаемая функцией epsilon(), определяемой в файле <limits>, представляет иашм ьш эпсилон для чисел с двойной точностью, то есть максимальное допустимое отклонение при сравнениях типов double. Вероятно, вы уже догадались, что переменной bufZ достается не остаток строки, а только следующее слово, ограниченное пропусками. В общем случае лучше использовать оператор , если вам известна точная последовательность данных во входном потоке, а преобразование осуществляется к типу, отличному от символьной строки. Впрочем, если потребуется прочитать сразу весь остаток строки и передать его в другой поток ввода-вывода, используйте функцию rdbuf(), как показано далее. При тестировании оператора для типа Date, представленного в начале главы, использовался строковый поток ввода со следующей тестовой программой: : C04:DateIOTest.cpp {L} ../C02/Date #include <iostream> linclude <sstream> linclude ../C02/Date.h using namespace std; void testDateCconst string& s) { istringstream os(s); Date d; OS d; if (OS) cout d endl: else cout input error with V s \ \n : int mainO {
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |