- •Классы потоков
- •Листинг 2. Форматирование с помощью манипуляторов
- •Листинг 3. Форматирующие флаги потоков
- •Состояние потока
- •Файловые потоки
- •Листинг 4. Примеры открытия файловых потоков
- •Бесформатный ввод-вывод
- •Класс istream
- •Класс ostream
- •Ввод-вывод с произвольным доступом
- •Листинг 5. Произвольный доступ к файлу
- •Заключение
Ввод-вывод с произвольным доступом
Понятие произвольного доступа к файлу подразумевает два, или даже три, различных момента. Во-первых, оно означает, что можно произвольно обращаться к любой записи или любому байту в файле, в противоположность последовательному доступу, когда данные извлекаются или передаются в поток строго по очереди. Во-вторых, предполагается, что на открытом файле можно произвольно чередовать операции чтения и записи. И, наконец, из сказанного вытекает, что ввод-вывод с произвольным доступом является по преимуществу бесформатным.
Приведенная ниже программа открывает (создает новый или переписывает старый) свой файл как двоичный, и, кроме того, сразу для ввода и вывода. Она применяет функции позиционирования потока и функции бесформатного чтения-записи.
Листинг 5. Произвольный доступ к файлу
//////////////////////////////////////////////////
// Random.cpp: Демонстрация файла с произвольным доступом.
//
#include <fstream.h>
#include <iomanip.h>
#pragma hdrstop
#include <condefs.h>
const int NP = 10;
const int IS = sizeof(int);
#pragma argsused
int main(int argc, char* argv[])
{
int pt, i;
//
// Открытие файла для чтения/записи.
//
fstream fs("random.pts",
ios::binary | ios::in | ios::out | ios::trunc);
if (ifs) {
cerr << "Failed to open file." << endl;
return (1);
}
//
// Первоначальная запись файла.
//
cout << "Initial data:" << endl;
for (i=0; i<NP; i++){
pt = i;
fs.write((char*)&pt, IS);
cout << setw(4) << pt;
}
cout << endl << endl;
//
// Чтение файла от конца к началу.
//
cout << "Read from the file in reverse order:"<< endl;
for (i=0; i<NP; i++) {
fs.seekg(-(i + 1) * IS, ios::end);
fs.read((char*)&pt, IS);
cout “ setw(4)<< pt; . }
cout<< end1 << end1;
//
// Переписать четные индексы.
//
for (i=l; i<NP/2; i++) {
fs.seekg(2 * i * IS) ;
fs.read((char*)&pt, IS);
pt = -pt;
fs.seekg(fs.tellg () - IS); // Возврат на шаг.
fs.write((char*)&pt, IS);
}
//
// Распечатать файл.
//
cout << "After rewriting the even records:"<<endl;
fs.seekg(0) ;
for (i=0; i<NP; i++) {
fs.read((char*)&pt, IS);
cout << setw(4) << pt;
}
cout << endl;
fs.close ();
return 0;
}
Примечание
Когда эта программа открывает уже существующий файл, он усекается до нулевой длины (т. е. все его данные теряются). Если вы хотите работать с имеющимися в файле данными, нужно убрать бит ios: :trunc из режима открытия потока. Кстати, в примере это можно сделать безболезненно — данные файла все равно сразу переписываются заново.
В этом примере мы пользовались для позиционирования потока функцией seekg () . Но поскольку поток у нас типа f stream, и открыт он в режиме чтения-записи, то все равно, какую функцию применять для позиционирования — seekg () или seekp () .
Примечание
He следует упускать из виду, что при выполнении операций бесформатного чтения или записи (read/write) указатель потока сдвигается вперед на число прочитанных (записанных) байтов. Вывод программы показан на рис. 4.
Рис. 4 Программа Random