Программирование >>  Разработка устойчивых систем 

1 ... 39 40 41 [ 42 ] 43 44 45 ... 196


Поиск в потоках ввода-вывода 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 {



1 ... 39 40 41 [ 42 ] 43 44 45 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика