C++ Программирование в среде С++ Builder 5

         

Ввод-вывод с произвольным доступом


Понятие произвольного доступа к файлу подразумевает два, или даже три, различных момента. Во-первых, оно означает, что можно произвольно обращаться к любой записи или любому байту в файле, в противоположность последовательному доступу, когда данные извлекаются или передаются в поток строго по очереди. Во-вторых, предполагается, что на открытом файле можно произвольно чередовать операции чтения и записи. И, наконец, из сказанного вытекает, что ввод-вывод с произвольным доступом является по преимуществу бесформатным.

Приведенная ниже программа открывает (создает новый или переписывает старый) свой файл как двоичный, и, кроме того, сразу для ввода и вывода. Она применяет функции позиционирования потока и функции бесформатного чтения-записи.

Листинг 9.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) указатель потока сдвигается вперед на число прочитанных (записанных) байтов.

Вывод программы показан на рис. 9.4.



Рис. 9.4 Программа Random



Заключение



Аппарат потоковых классов библиотеки C++ довольно громоздок, если сравнивать его, например, с функциями языка С вроде printf (). Однако средства потоков C++ единообразны, надежны и расширяемы. Как вы узнали из этой главы, можно достаточно просто перегрузить операции извлечения и передачи, чтобы с точки зрения потоков ввода-вывода определенный вами тип выглядел бы подобно встроенным типам данных.

В следующей главе мы займемся шаблонами — средством C++, которое позволяет создавать “обобщенные” классы, служащие моделью некоторого множества конкретных классов.


Содержание раздела