- •Ввод-вывод в языке с
- •Потоковые функции
- •Открытие файлов и потоков
- •Переадресация ввода-вывода
- •Изменение буфера потока
- •Форматный вывод данных
- •Функция printf()
- •Поиск в файлах с помощью функций fseek( ), ftell( ) и rewind()
- •Синхронный и асинхронный ввод/вывод
- •3. Позиционирование указателя файла.
- •6. Запись данных в файл
- •Блокировка и разблокировка файла
- •Асинхронный режим чтения и записи файлов
- •Стандартные потоки cin, coutи cerr
- •Флаги и функции форматирования
- •Файловый ввод-вывод
- •Флаг Назначение
- •Файловый ввод
- •Файловый вывод
- •Вот результаты работы программы:
- •Двоичные файлы
- •Буферы потоков
Двоичные файлы
Следующая программа аналогична предыдущему примеру и иллюстрирует, что произойдет, если ту же самую строку вывести в тот же самый файл, только открытый в двоичном режиме.
// // binary.срр // Эта программа является модификацией предыдущего примера // и демонстрирует работу с файлом,открытым в двоичном режиме. //
#include <fstream > #include <string.h>
#define iSTRING_MAX 40
void main () {
int i = 0;
char pszString [iSTRING_MAX] = "Записываемая строка\n";
// файл открывается в двоичном режиме
ofstream ofMyOutputStream("OFSTREAM.OUT", ios :: binary)
// строка выводится символ за символом; // обратите внимание, что символ ' \n ' // никак не преобразуется while (pszString [i]!= '\0') {
ofMyOutputStream.put (pszString [i]);
cout <<' "\nПозиция маркера записи: << ofMyOutputStream.tellp() ;
i++;}
// запись всей строки целиком
ofMyOutputStream.write(pszString, strlen(pszString)),
cout<< "\nНовая позиция маркера записи: "<< ofMyOutputStream.tellp() ; ofMyOutputStream.close() ; }
Вот результаты работы программы:
Позиция маркера записи: 1
Позиция маркера записи: 2
Позиция маркера записи: 3
Позиция маркера записи: 18
Позиция маркера записи: 19
Позиция маркера записи: 20
Новая позиция маркера записи: 40
При выводе строки pszString не происходит замены концевого символа \n парой символов возврата каретки и перевода строки, поэтому в поток записывается 20 символов — ровно столько, сколько содержится в строке.
Буферы потоков
В основе всех буферизованных потоков ввода-вывода в C++ лежит класс streambuf. В этом классе описаны основные операции, выполняемые над буферами ввода-вывода (табл. 10). Любой класс, порожденный от ios, наследует указатель на объект класса streambuf. Именно последний выполняет реальную работу по вводу и выводу данных.
Объекты класса streambuf управляют фиксированной областью памяти, называемой также областью резервирования. Она, в свою очередь, может быть разделена на область ввода и область вывода, которые могут перекрывать друг друга.
Класс streambuf является абстрактным, т.е. создать его объект напрямую нельзя (его конструктор является защищенным и не может быть вызван из программы). В то же время, имеются три производных от него класса, предназначенные для работы с потоками конкретного типа: filebuf (буферы дисковых файлов), strstreambuf (строковые буферы, хранящиеся в памяти) и stdiobuf (буферизация дискового ввода-вывода с помощью стандартных системных функций). Кроме того, можно создавать собственные классы, порожденные от streambuf, переопределяя его виртуальные функции (табл. 11) и настраивая, таким образом, его работу в соответствии с потребностями конкретного приложения. Только из производных классов можно вызывать и многочисленные защищенные функции этого класса, управляющие областью резервирования (табл. 12).
Таблица 10. Открытые функции класса streambuf |
|
Открытая функция |
Описание |
in_avail |
Возвращает число символов в области ввода |
sgetc |
Возвращает символ, на который ссылается указатель области ввода; при этом указатель не перемещается |
snextc |
Перемещает указатель области ввода на одну позицию вперед, после чего возвращает текущий символ |
sbumpc |
Возвращает текущий символ и затем перемещает указатель области ввода на одну позицию вперед |
stossc |
Перемещает указатель области ввода на одну позицию вперед, но не возвращает символ |
sputbaqkc |
Перемещает указатель области ввода на одну позицию назад, возвращая символ в буфер |
sgetn |
Читает требуемое количество символов из буфера |
out_waiting |
Возвращает число символов в области вывода |
sputc |
Записывает символ в буфер и перемещает указатель области вывода на одну позицию вперед |
sputn |
Записывает требуемое количество символов в буфер и перемещает указатель области вывода на соответствующее число позиций |
dbp |
В текстовом виде записывает в стандартный выходной поток различного рода информацию о состоянии буфера |
Таблица 11. Виртуальные функции класса streambuf |
|
Виртуальная функция |
Описание |
sync |
Очищает области ввода и вывода |
setbuf |
Добавляет к буферу указанную зарезервированную область памяти |
seekoff |
Перемещает указатель области ввода или вывода на указанное количество байтов относительно текущей позиции |
seekpos |
Перемещает указатель области ввода или вывода на указанную позицию относительно начала потока |
overflow |
Очищает область вывода |
underflow |
Если область ввода пуста, заполняет ее данными из источника |
pbackfail |
Вызывается функцией sputbackc() в случае неудачной попытки вернуться назад на один символ |
Таблица 12. Защищенные функции класса streambuf |
|
Защищенная функция |
Описание |
base |
Возвращает указатель на начало области резервирования |
ebuf |
Возвращает указатель на конец области резервирования |
blen |
Возвращает размер области резервирования |
phase |
Возвращает указатель на начало области вывода |
pptr |
Возвращает значение указателя области вывода |
epptr |
Возвращает указатель на конец области ввода |
eback |
Возвращает указатель на начало области ввода |
gptr |
Возвращает значение указателя области ввода |
egptr |
Возвращает указатель на конец области вывода |
setp |
Задает значения указателей, связанных с областью вывода |
setg |
Задает значения указателей, связанных с областью ввода |
pbump |
Перемещает указатель области вывода на указанное число байтов относительно текущей позиции |
gbump |
Перемещает указатель области ввода на указанное число байтов относительно текущей позиции |
setb |
Задает значения указателей, связанных с областью резервирования |
unbuffered |
Задает или возвращает значение переменной, определяющей состояние буфера |
allocate |
Вызывает виртуальную функцию deallocate для создания области резервирования |
deallocate |
Выделяет память для области резервирования (виртуальная функция) |
Классы файловых потоков, такие как ifstream, ofstream и fstream, содержат встроенный объект класса filebuf, который вызывает низкоуровневые системные функции для управления буферизованным файловым вводом-выводом. Для объектов класса filebuf области ввода и вывода, а также указатели текущей позиции чтения и записи всегда равны друг другу. Функции этого класса перечислены в табл. 13.
Таблица 13.Функции класса filebuf |
|
Функция |
Описание |
open |
Открывает файл, связывая с ним объект класса filebuf |
close |
Закрывает файл, "выталкивая" все содержимое области вывода |
setmode |
Задает режим доступа к файлу: двоичный (константа filebuf:: binary) или текстовый (константа filebuf: :text) |
attach |
Связывает указанный открытый файл с объектом класса filebuf |
fd |
Возвращает дескриптор файла |
is_open |
Проверяет, открыт ли файл, связанный с потоком |
В следующей программе создаются два файловых объекта: fbMylnputBuf и fbMyOutputBuf. Оба они открываются в текстовом режиме с помощью функции open(): первый — для чтения, второй — для записи. Если при открытии файлов не возникнет никаких ошибок, то каждый из них связывается с соответствующим объектом класса istream и ostream. Далее в цикле while символы читаются из файла fbMylnputBuf с помощью функции get() класса istream и записываются в файл fbMyOutputBuf с помощью функции put() класса ostream. Подсчет числа строк осуществляется с помощью выражения
iLineCount += (ch == '\n');
Когда в поток помещается символ \n, выражение в скобках возвращает 1 и счетчик iLineCount увеличивается на единицу, в противном случае он остается неизменным.
Оба файла закрываются с помощью функции close().
// // filebuf.cpp // Эта программа на языке C++ демонстрирует, как работать // с объектами класса filebuf. //
#include <f stream. h>
t#include <process.h> // содержит прототип функции exit()
void main (void)
{
char ch;
int iLineCount = 0;
filebuf fbMyInputBuf, fbMyOutputBuf;
fbMyInputBuf .open ("FILEBUF.CPP", ios::in);
if (fbMylnputBuf .is_open()== 0) {
cerr<< "Невозможно открыть файл для чтения";
exit (1);
}
istream is(SfbMylnputBuf) ;
fbMyOutputBuf.open("output.dat",ios::out);
if(fbMyOutputBuf.is_open() == 0) {
cerr<< "Невозможно открыть файл для записи";
exit(2); }
ostream os(SfbMyOutputBuf);
while (is) {
is.get(ch);
os.put(ch);
iLineCount += (ch== '\n');
}
bMylnputBuf. close (); fbMyOutputBuf.close();
cout << "Файл содержит " << iLineCount << " строк";
}
Cтроковые буферы
Класс strstreambuf управляет символьным буфером, расположенным в динамической памяти.
Несколько примеров форматного вывода данных
В первом примере на экран выводится список факториалов чисел от 1 до 25 с выравниванием влево:
// // fact.cpp // Эта программа на языке C++ выводит список факториалов чисел от 1 до 25. //
#include <iostream.h> main ()
{ double number = 1.0,factorial = 1.0;
cout .precision (0); //0 цифр после запятой
cout .setf (ios:: left) ; // выравнивание влево
cout .setf (ios:: fixed) ; // фиксированный формат (безэкспоненты)
for(int i =0; i < 25;i++) {
factorial *= number++;
cout << factorial << endl; }
return(0); }
Результаты работы программы будут такими:
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
51090942171709440000
1124000727777607680000
25852016738884976640000
620448401733239439360000
15511210043330985984000000
Во втором примере на экран выводится таблица квадратов и квадратных корней целых чисел от 1 до 15.
// // sqrt.cpp // Эта программа на языке C++ строит таблицу квадратов и квадратных // корней чисел от 1 до 15. //
#include <iostream.h> # include <math.h>
main () {
double number =1.0,square, sqroot;
cout << "Число\tKвaдрат\t\tKвадратный корень\n";
cout << " ______________________________________ \n";
cout .setf (ios:: fixed) ; // фиксированный формат (без экспоненты)
for(int i = 1; i < 16;i++) {
square = number * number; // вычисление квадрата числа sqroot = sqrt(number); // нахождение корня числа
cout.fill('0'); // заполнение недостающих позиций нулями cout.width(2); // ширина столбца — минимум 2 символа cout.precision(0); // 0 цифрпосле запятой cout << number << "\t";
cout.fill(' '); // использовать пробел в качестве заполнителя cout << square << "\t\t";
cout.precision(6); // 6 цифр после запятой cout<< sqroot<< endl;
number++; }
return(0); }
Программа выведет следующую таблицу чисел:
число корень квадратный корень
01 |
1 |
1.000000 |
|
02 |
4 |
1.414214 |
|
03 |
9 |
1.732051 |
|
04 |
16 |
2.000000 |
|
05 |
25 |
2..236068 |
|
06 |
36 |
2.449490 |
|
07 |
49 |
2.645751 |
|
08 |
64 |
2.828427 |
|
09 |
81 |
3.000000 |
|
10 |
100 |
3.162278 |
|
11 |
121 |
3.316625 |
|
12 |
144 |
3.464102 |
|
13 |
169 |
3.605551 |
|
14 |
196 |
3.741657 |
|
15 |
225 |
3.872983 |
|