- •Ввод-вывод в языке с
- •Потоковые функции
- •Открытие файлов и потоков
- •Переадресация ввода-вывода
- •Изменение буфера потока
- •Форматный вывод данных
- •Функция printf()
- •Поиск в файлах с помощью функций fseek( ), ftell( ) и rewind()
- •Синхронный и асинхронный ввод/вывод
- •3. Позиционирование указателя файла.
- •6. Запись данных в файл
- •Блокировка и разблокировка файла
- •Асинхронный режим чтения и записи файлов
- •Стандартные потоки cin, coutи cerr
- •Флаги и функции форматирования
- •Файловый ввод-вывод
- •Флаг Назначение
- •Файловый ввод
- •Файловый вывод
- •Вот результаты работы программы:
- •Двоичные файлы
- •Буферы потоков
Флаги и функции форматирования
Работа всех потоковых объектов из библиотеки IOSTREAM контролируется флагами форматирования, определяющими такие параметры, как, например, основание системы счисления при выводе целых чисел и точность представления чисел с плавающей запятой.
Флаги можно устанавливать с помощью функции setf(), а сбрасывать — с помощью функции unsetf (). Есть два варианта функции setf() с одним аргументом типа long и с двумя. Первым аргументом является набор флагов, объединенных с помощью операции побитового ИЛИ (|). Возможные флаги перечислены в таблице 5.
Таблица 5. Флаги форматирования |
|
Флаг |
Назначение |
skipws |
при вводе пробельные литеры пропускаются |
left |
выводимые данные выравниваются по левому краю с дополнением символами-заполнителями по ширине поля |
right |
выводимые данные выравниваются по правому краю с дополнением символами-заполнителями по ширине поля (установлен по умолчанию) |
internal |
при выравнивании символы-заполнители вставляются между символом знака или префиксом основания системы счисления и числом |
dec |
целые числа выводятся по основанию 10 (установлен по умолчанию); устанавливается также манипулятором dec |
oct |
целые числа выводятся по основанию 8; устанавливается также манипулятором oct |
hex |
целые числа выводятся по основанию 16; устанавливается также манипулятором hex |
showbase |
при выводе целых чисел отображается префикс, указывающий на основание системы счисления |
showpoint |
при выводе чисел с плавающей запятой всегда отображается десятичная точка, а хвостовые нули не отбрасываются |
uppercase |
шестнадцатеричные цифры от А до F, а также символ экспоненты Е отображаются в верхнем регистре |
showpos |
при выводе положительных чисел отображается знак плюс |
scientific |
числа с плавающей запятой отображаются в научном формате (с экспонентой) |
fixed |
числа с плавающей запятой отображаются в фиксированном формате (без экспоненты) |
unitbuf |
при каждой операции вывода буфер потока должен очищаться |
stdio |
при каждой операции вывода буферы потоков stdout и stderr должны очищаться |
Вторым аргументом является специальная битовая маска, определяющая, какую группу флагов можно модифицировать. Имеются три стандартные маски:
adjustfield = internal | left | right
basefield = dec | oct | hex
floatfield = fixed | scientific
Оба варианта функции setf() возвращают значение типа long, содержащее предыдущие установки всех флагов.
Все перечисленные флаги, а также константы битовых масок и упоминавшиеся манипуляторы dec, hex и oct являются членами класса ios - базового в иерархии всех классов ввода-вывода. В этот класс входят, помимо прочего, функции fill() , precision ( ) и width ( ) , тоже связанные с форматированием выводимых данных!
Функция fill( ) устанавливает переданный ей символ в качестве символа-заполнителя. Аналогичные действия выполняет манипулятор setfill() . Вызванная без аргументов, функция возвращает текущий символ-заполнитель. По умолчанию таковым служит пробел.
Когда установлен флаг scientific или fixed, функция precision() задает точность представления чисел с плавающей запятой, в противном случае определяет общее количество значащих цифр. Аналогичные действия выполняет манипулятор setprecision() . По умолчанию точность равна 6. Вызванная без аргументов, функция возвращает текущее значение точности.
Функция width() определяет минимальную ширину поля вывода в символах. Если при выводе количество символов оказывается меньшим ширины поля, оно дополняется специальными символами-заполнителями. После каждой операции записи значение ширины поля сбрасывается в 0. Аналогичные действия выполняет манипулятор setw( ) . Вызванная без аргументов, функция возвращает текущую ширину поля.
Манипуляторы setfill () , setprecision() и setw(), также являющиеся членами класса ios, относятся к категории параметризованных, и для работы с ними необходимо дополнительно подключить к программе файл IOMANIP.
Следующая программа является написанным на C++ аналогом программы printf.c, рассмотренной в предыдущей главе.
// // ioflags.cpp // Эта программа на языке C++ демонстрирует применение // флагов и функций форматирования. //
#include <strstrea.h>
#define MAX_LENGTH 20
void row ();
main{) {
char с = 'A', psz[] = "Строка для экспериментов", strbuffer[MAX_LENGTH];
int ivalue = 1234;
double dPi = 3.14159265;
// вывод символа с row(); // [ 1] cout<< с;
// вывод ASCII-кода символа с row() ; // [2] cout << (int)c;
// вывод символа с ASCII-кодом 90
row (); // [ 3]
cout << (char)90;
// вывод значения ivalue в восьмеричной системе
row(); //[4]
cout << oct << ivalue;
// вывод значения ivalue в шестнадцатеричной системе
//сбуквами в нижнем регистре
row (); // [5]
cout << hex << ivalue;
// вывод значения ivalue в шестнадцатеричной системе
// с буквами в верхнем регистре
row (); // [ 6]
cout.setf(ios::uppercase);
cout << hex << ivalue;
cout.unsetf(ios::uppercase); // отмена верхнего регистра символов
cout<< dec; // возврат к десятичной системе
// вывод одного символа, минимальная ширина поля равна 5, // выравнивание вправо с дополнением пробелами row();// [ 7] cout.width(5); cout<< с;
// вывод одного символа, минимальная ширина поля равна 5,
// выравнивание влево с дополнением пробелами
row(); // [ 8]
cout.width(5);
cout.setf(ios::left);
cout << c;
cout.unsetf(ios::left);
// вывод строки, отображаются 24 символа row();// [9] cout<< psz;
// вывод минимум 5-ти символов строки row();// [10] cout.width(5); cout<< psz;
// вывод минимум 38-ми символов строки,
// выравнивание вправо с дополнением пробелами
row();// [11]
cout.width(38); cout << psz;
// вывод минимум 38-ми символов строки,
// выравнивание влево с дополнением пробелами
row ();// [12]
cout.width(38);
cout.setf(ios::left);
cout << psz;
cout.unsetf(ios::left);
// вывод значения ivalue, по умолчанию отображаются 4 цифры row();// [13] cout<< ivalue;
// вывод значения ivalue со знаком
row ();// [14]
cout.setf(ios::showpos);
cout << ivalue;
cout.unsetf(ios::showpos) ;
// вывод значения ivalue минимумиз 3-х цифр, отображаются 4 цифры row ();// [15] cout.width(3); cout << ivalue;
// вывод значения ivalue минимум из 10-ти цифр, } // выравнивание вправо с дополнением пробелами row();// [16] cout.width(10); cout<< ivalue;
// вывод значения ivalue минимум из 10-ти цифр,
// выравнивание влево с дополнением пробелами
row();// [17]
cout.width(10);
cout.setf(ios::left) ;
cout << ivalue;
cout.unsetf(ios::left);
// вывод значения ivalue минимум из 10-ти цифр,
// выравнивание вправо с дополнением нулями
row (); // [18]
cout.width (10);
cout.fill ('0');
cout << ivalue;
cout.fill (' ');
// вывод значения dPiс форматированием по умолчанию row(); // [19] cout<< dPi;
// вывод значения dPi, минимальная ширина поля равна 20, // выравнивание вправо с дополнением пробелами row{); // [20] cout.width (20); cout<< dPi;
// вывод значения dPi, минимальная ширина поля равна 20,
// выравнивание вправо с дополнением нулями
row();// [21]
cout.width(20);
cout.fill('0');
cout << dPi;
cout. fill (' ');
// вывод значения dPi, минимальная ширина поля равна 20,
// выравнивание влево с дополнением пробелами
row();// [22]
cout.width(20);
cout.setf(ios::left) ;
cout<< dPi;
// вывод значения dPi, минимальная ширина поля равна 20,
// выравнивание влево с дополнением нулями
row();// [23]
cout.width(20);
cout. fill ('0');
cout << dPi;
cout.unsetf(ios::left);
cout.fill(' ');
// вывод 19-ти символов строки, минимальная ширина поля равна 19
row();// [24]
ostrstream(strbuffer, 20).write(psz,19)<< ends;
cout.width(19);
cout << strbuffer;
// вывод первых двух символов строки
row(); // [25]
ostrstream(strbuffer, 3).write(psz,2) << ends;
cout<< strbuffer;
// вывод первых двух символов строки, минимальная ширина поля равна 19, // выравнивание вправо с дополнением пробелами
row();// [26] cout.width(19); cout << strbuffer;
// вывод первых двух символов строки, минимальная ширина поля равна 19, // выравнивание влево с дополнением пробелами row();// [27] cout.width(19);
cout .setf (ios :: left) ; cout << strbuffer; cout .unsetf (ios :: left) ;
// вывод значенияdPi из5-ти значащих цифр row ();// [28] cout .precision (9); cout << dPi;
// вывод значения dPiиз 2-х значащих цифр, минимальная ширина поля
// равна 20, выравнивание вправо с дополнением пробелами
row ();// [29]
cout. width (20) ;
cout .precision (2);
cout << dPi;
// выводзначенияdPi из 4-хзначащихцифр row () ; // [30] cout .precision (4); cout << dPi;
// вывод значения dPi из 4-х значащих цифр, минимальная ширина поля // равна 20, выравнивание вправо с дополнением пробелами row(); // [31] cout. width(20); cout<< dPi;
// вывод значения dPi, минимальная ширина поля равна 20,
// 4 цифры после десятичной точки, выравнивание вправо
IIс дополнением пробелами, научный формат (с экспонентой)
row ();// [32]
cout . setf (ios :: scientific) ;
cout. width ( 20 );
cout << dPi;
cout. unset f (ios: : scientific );
return (0);
}
void row() {
static int ln = 0;
cout << " \n [";
cout.width(2) ;
cout<< ++ln<< "] "; }
Результат работы программы будет выглядеть следующим образом:
[ 1] А
[ 2] 65
[ 3] Z
[ 4] 2322
[ 5] 4d2
[ 6] 4D2
[ 7]А
[ 8]А
[ 9] Строка для экспериментов
[10] Строка для экспериментов
[11]' Строка для экспериментов
[12]Строка для экспериментов
[13]1234
[14]+1234
[15]1234
[16]1234
[17] 1234
[18] 0000001234
[19] 3.14159
[20] 3.14159
[21] 00000000000003.14159
[22] 3.14159
[23] 3.141590000000000000
[24] Строка для эксперим
[25] Ст
[26] Ст
[27] Ст
[28] 3.14159265
[29] 3.1
[30] 3.142
[31]3.142
[32] 3.1416e+000
В этой программе следует обратить внимание на использование класса ostrstream в пунктах 24 и 25, а также неявно в пунктах 26 и 27. Этот класс управляет выводом строк. Необходимость в нем возникла в связи с тем, что флаги форматирования оказывают влияние на работу оператора <<, но не функции write() класса ostream(класс ostrstream является его потомком и наследует данную функцию), которая записывает в поток указанное число символов строки. Выводимые ею данные всегда прижимаются к левому краю. Поэтому мы поступаем следующим образом:
ostrstream(strbuffer, 20).write(psz,19)<< ends; cout.width(19); cout << strbuffer;
Разберем этот фрагмент шаг за шагом. Сначала вызывается конструктор класса ostrstream, создающий временный безымянный объект данного класса, автоматически уничтожаемый по завершении строки. Если вы еще не знакомы с понятием конструктора, то поясним, что это особая функция, предназначенная для динамического создания объектов своего класса. Конструктор класса ostrstream требует указания двух аргументов: буферной строки, в которую будет осуществляться вывод, и размера буфера. Особенность заключается в том, что реальный размер буферного массива может быть больше указанного, но все данные, записываемые сверх лимита, будут отсекаться.
Итак, конструктор создал требуемый объект, связанный с буфером strbuffer. Этот объект является обычным потоком в том смысле, что им можно управлять как и любым другим потоком вывода, только данные будут направляться не на экран, а в буфер. Вторым действием вызывается функция write() объекта, записывающая в поток первые 19 символов строки psz. Оператор точка (.) в данном случае обозначает операцию доступа к члену класса. Здесь тоже есть своя особенность: функция write() возвращает адрес потока, из которого она была вызвана. А это, в свою очередь, означает, что мы можем тут же применить к потоку оператор вывода <<. Итого, три действия в одном выражении! Манипулятор ends класса ostream вставляет в поток символ \0,служащий признаком завершения строки. Именно поэтому в буфере было зарезервировано 20 ячеек — на единицу больше, чем количество выводимых символов строки psz. В результате выполненных действий в буфере оказалась сформированной готовая строка, которая, в конце концов, и направляется в поток cout.
Теперь рассмотрим, что происходит в пункте 25:
ostrstream (strbuf fer, 3) .write (psz, 2) << ends; cout << strbuffer;
Последовательность действий та же, но резервируется не весь буфер, а только первые три ячейки. Трюк в том, что объект cout воспринимает массив strbuffer как обычную строку, но поскольку в третьей ячейке стоит символ \0,то получается, что строка состоит из двух символов! В пунктах 26 и 27 используется содержимое буфера, полученное в пункте 25.
Важно также помнить, что функция width( ) оказывает влияние только на следующий за ней оператор вывода, тогда как, например, действие функции precision() останется в силе до тех пор, пока она не будет выполнена снова либо не будет вызван манипулятор setprecision( ) .