Произвольный доступ к элементам файлов

Файловый указатель.

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

При последовательном доступе к элементам файлов перемещение файлового указателя происходит автоматически. Но иногда бывает нужно контролировать его состояние. Для этого используются следующие функции:

- seekg() – установить текущий указатель чтения;

- tellg() – проверить текущий указатель чтения;

- seekp() – установить текущий указатель записи;

- tellp() – проверить текущий указатель записи.

Организация доступа к элементам двоичных файлов.

Благодаря наличию файлового указателя, в двоичных файлах допустим произвольный доступ к их элементам, который можно реализовать с помощью перегруженных функций – элементов, унаследованных из класса istream:

istream &seekg(streampos) или

istream &seekg(streamoff, ios::seek_dir);

Типы данных streampos и streamoff эквивалентны значениям типа long, но использовать long в явном виде не рекомендуется из-за неоднозначности работы различных компиляторов. Поэтому их определяют как

typedef long streampos;

typedef long streamoff;

Первая из перегруженных форм функции seekg позиционирует входной поток на заданном байте, вторая – на смещении относительно одной из трех позиций, определенных значением константы ios::seek_dir (табл. 1)

Таблица 1

Константа Значение Описание
beg 0 поиск от начала файла
cur 1 поиск от текущей позиции файла
end 2 поиск от конца файла

Для позиционирования внутреннего указателя файла для выходных потоков используют перегруженные функции выходных файловых потоков, унаследованных из класса ostream:

ostream &seekp(streampos);

ostream &seekp(streamoff, ios::seek_dir);

Пример 5. В двоичном файле, содержащем целые числа, заменить максимальное значение файла суммой его четных элементов.

 

#include <fstream>

#include <iostream>

 

using namespace std;

 

class bin_stream :public fstream {

public:

bin_stream(const char *fn) : fstream(fn, ios::out | ios::in | ios::binary) {}

void doneOurDate(const void*, int, int);

bin_stream &operator<<(int d) {

doneOurDate(&d, sizeof(d), 0);

return *this;

}

bin_stream &operator>>(int &d) {

doneOurDate(&d, sizeof(d), 1);

return *this;

}

};

 

int main()

{

int i, d, max, i_max, sum_even = 0;

bin_stream bin_out("Bin.dat");

if (!bin_out) {

cerr << "Unable to write to Bin.dat" << endl;

system("pause");

exit(1);

}

for (i = 0; i < 10; i++) {

d = rand() % 100;

bin_out << d;

if (d % 2 == 0) sum_even += d;

}

bin_out.seekp(0, ios::beg);

bin_out >> max;

i_max = 0;

for (i = 1; i < 10; i++) {

bin_out >> d;

if (d > max) { max = d; i_max = i; }

}

bin_out.seekp(sizeof(int)* i_max, ios::beg);

bin_out << sum_even;

bin_out.seekp(0, ios::beg);

for (i = 0; i < 10; i++) {

bin_out >> d;

cout << d << ' ';

}

bin_out.close();

cout << endl;

system("pause");

return 0;

}

 

void bin_stream::doneOurDate(const void *Ptr, int len, int sign)

{

if (!Ptr)

return;

if (len <= 0)

return;

if (sign == 0)

write((char*)Ptr, len);

else

read((char*)Ptr, len);

}

Контрольные вопросы

  1. Что такое поток?
  2. Особенности работы с двоичными файлами.
  3. Что представляет собой файловый указатель?
  4. Как организовать доступ к произвольному месту двоичного файла?

Пример компоновки формы программы к лабораторной работе