На этом шаге мы рассмотрим создание и использование выходных строковых потоков.
Выходные строковые потоки обычно создаются с помощью такого конструктора класса ostrstream:
ostrstream имя_потока(char *str, int len, int mode);
Вместе с флагом ios::out могут быть указаны (в дизъюнктивной форме) флаги ios::ate или ios::арр. В обоих случаях при формировании потока позиция записи устанавливается на нулевой признак '\0' конца строки (буфера потока), т.е. предполагается запись в конец потока.
По умолчанию выбирается ios::out, т.е. строковый поток создается для вывода (записи) информации с начала строки (буфера).
Начнем рассмотрение основных возможностей выходных строковых потоков с их безымянного варианта. В следующей программе значение строки обязательного аргумента функции main с помощью операции вставки << переносится в безымянный строковый поток, связанный с символьным массивом path[]:
//OOР15_1.СРР - запись в безымянный выходной строковый поток (<<). #include <strstrea.h> void main(int Narg, char *arg[]) { char path [80] ; ostrstream(path,sizeof(path)) << arg[0] << '\0'; cout<< "\nПолное имя программы: " << path << endl; }
Результат выполнения программы:
Полное имя программы: D:\WWP\TESTPROG\OOP52_1.EXE
Так как операция включения << не переносит в выходной поток признак конца строки '\0', то его пришлось явным образом поместить в выходной поток (тем самым в буфер path[]).
Функция write() применительно к выходному потоку позволяет записывать в него данные без форматирования, т.е. строка записывается вместе с пробельными символами и символом конца строки '\0'. Чтобы продемонстрировать особенности ее применения к безымянным выходным строковым потокам, рассмотрим следующую программу:
//OOР15_2.СРР - запись в безымянный выходной строковый // поток; копирование строки с использованием функции write(). #include <strstrea.h> void main () { char lat[] = "Quod erat demonstrandum!"; char rus[] = " - Что и требовалось доказать!"; char result[60]; ostrstream(result, sizeof (result)) .write (lat, sizeof (lat)); ostrstream(result, sizeof (result) , ios::ate) .write (rus, sizeof (rus)); cout << "\n" << result << endl; }
Результат выполнения программы:
Quod erat demonstrandum! - Что и требовалось доказать!
В программе два безымянных потока, каждый из которых "настроен" на символьный массив result[]. При создании первого безымянного потока в качестве параметров конструктора указываются - массив result[] и его размеры, т.е. длина массива в байтах. Функция write() "присоединяется" с помощью операции "точка" непосредственно к конструктору и тем самым вызывается для созданного им безымянного потока. В качестве фактических параметров функции write() используются указатель lat на строку и количество записываемых символов. Так как длина строки меньше длины буфера result, то буфер не заполняется целиком. При создании второго безымянного потока, кроме буфера result и его длины, в конструкторе (в качестве третьего параметра) использован флаг ios::ate, под действием которого поток создается как "дополняемый". Тем самым последующая запись в поток выполняется не с начала потока, а начиная с позиции окончания предыдущей записи '\0'. Именно тут функция write() помещает строку, адресованную указателем rus. Та самым в массиве result[] осуществляется конкатенация строк, что видно из результатов. Из массива result [] вывод в поток cout выполняется до появления символа конца строки ' \0' в массиве result.
Следующая программа иллюстрирует особенности последовательного вывода в строковый поток данных разных типов с помощью операции включения:
//OOР15_3.СРР - вывод в строковый поток операцией <<. #include <strstrea.h> void main() { char buffer[180]; ostrstream outstring(buffer, sizeof(buffer), ios::out | ios::ate); outstring << "\nБез явного включения разделителей" << " текст в потоке\n\"сливается\":\n "; outstring << 123456789 << -456 << +1.23456789; outstring << -0.123456789e+1 << +123.456789e-3 << ends; cout << "\n" << buffer << endl; }
Результат выполнения программы:
Без явного включения разделителей текст в потоке "сливается": 123456789-4561.23456789-1.23456780.123457
Как показывают результаты, последовательное обращение к строковому потоку приводит к записи "в продолжение", т.е. указатель позиции записи при создании потока устанавливается на его начало, а затем перемещается на длину каждой новой записи. Никаких промежутков или разделителей между выводимыми данными не добавляется. Более того, операция включения в поток << даже не переносит в него нулевой ограничитель конца строки '\0'. Поэтому его нужно добавлять явно, если в дальнейшем требуется использовать буфер потока в качестве строки. Числовая информация, включаемая в поток операцией <<, форматируется. При этом знак + для чисел заменяется пробелом, вещественные числа, заданные в экспоненциальной форме (в научной нотации), переводятся в форму с фиксированной точкой. Выполняется округление дробной части вещественного числа. Перечисленные и проиллюстрированные результатами особенности форматирования могут быть изменены с помощью средств управления форматом как и для стандартных потоков.
На следующем шаге мы рассмотрим двунаправленные строковые потоки.