Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛекцииЛаб(Часть_2_Книги).doc
Скачиваний:
4
Добавлен:
03.05.2019
Размер:
988.16 Кб
Скачать

§4. Прямой (произвольный) доступ к файлу

Файл можно рассматривать как последовательность байтов. Каждому из них можно присвоить порядковый номер, начиная с нуля. Тогда любой байт файла можно найти по его номеру.

Как было сказано в 1.2, место, откуда выполняется чтение информации из файла, или куда происходит запись данных, определяется положением указателя чтения-записи файла. Его положение — это порядковый номер байта, который будет считан первым или который первым получит новое значение. Заметим, что здесь термин “указатель” никак не связан с типом переменной, значением которой является адрес. Начальная позиция этого “невидимого курсора” устанавливается при открытии потока и указывает на начало потока при создании и чтении файла (режимы “r” и “w”) или на его конец при добавлении данных (режим “a”).

При операции чтения или записи указатель автоматически сдвигается “вперёд”, а, точнее, к концу файла, на то число байтов, которое было прочитано или записано. Если при операции чтения был достигнут конец файла, возникнет ситуация EOF. Если конец файла был достигнут при операции записи, то конец файла автоматически перемещается на то число байтов, которое было записано за прежним концом файла.

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

4.1. Функция fseek()

Наибольшими возможностями позиционирования указателя потока обладает функция int fseek (FILE *f, long offset, int from). Она сдвигает указатель в файле f на offset байт от положения, указанного третьим параметром from.

Чаще всего from принимает значение SEEK_SET или, что то же самое, нулевое значение. Тогда указатель файла перемещается на offset байт “вперёд” от начала потока в сторону конца файла, если offset>=0. В этом случае offset задаёт порядковый номер байта, на который надо установить указатель чтения-записи. При таком нулевом значении параметра from параметр offset не должен быть отрицательным. Например,

int a; fseek(f, 20, SEEK_SET); a=fgetc(f); // ??????

прочитает информацию, начиная с 20-го байта двоичного файла, который желательно открывать с режимом “rb”.

Если from=SEEK_END, что соответствует целому числу 2, то при неположительном значении параметра offset указатель файла перемещается на |offset| байт “назад” от конца потока в сторону начала файла. При таком значении параметра from параметр offset не должен быть положительным. В противном случае мы “выйдем” за границу файла.

Если from=SEEK_CUR, что соответствует целому числу 1, то можно “продвигаться” на offset байт “вперёд” от текущей позиции указателя при offset>0, или “назад” к началу файла, если offset<0.

Функция fseek() возвращает 0 в случае успешного выполнения и ненулевое значение в случае ошибки.

Пример 1. Прямой доступ к файлу. Прочитать и вывести на экран n-й одномерный массив фиксированной размерности m, (n-2)-й массив, (n-4)-й массив и т. д. до начала файла.

const m=5,

n=8;

FILE *arf;

// Создание файла. Объяснение смотри в 3.2

void MyCr()

{ int a[m];

arf= fopen("d:\\ANA\\cpp\\2004_05\\farr2.dat","wb");

printf("\n");

for (int i=0; i<n;i++)

{ cout<<endl;

for (int j=0;j<m;j++)

{ a[j]=(i+1)*(j+1);

printf("%5d",a[j]);

}

fwrite (a, sizeof(a),1, arf);

}

fclose(arf); cout<<"\nFile was created"; }

// Просмотр файла. Объяснение смотри в 3.2

void MyRead()

{ int a[m];

arf= fopen("d:\\ANA\\cpp\\2004_05\\farr2.dat","rb");

fread(a,sizeof(a),1,arf);

while (!feof(arf))

{

printf("\n");

for (int j=0;j<m;j++)

printf("%5d",a[j]);

fread(a,m*sizeof(int),1,arf);

}

fclose(arf);

}

/* Вариант 1. Указатель файла перемещаем, используя в функции fseek () позицию начала файла, т. е. в качестве последнего параметра этой функции используем SEEK_SET */

void MyRead1()

{ int a[m];

arf= fopen("d:\\ANA\\cpp\\2004_05\\farr2.dat","rb");

for (int i=1; i<=n;i+=2)

{ fseek(arf, (n-i)*sizeof(a),SEEK_SET);

fread(a,sizeof(a),1,arf);

printf("\n");

for (int j=0;j<m;j++)

printf("%5d",a[j]);

}

fclose(arf);

}

/* Вариант 2. Указатель файла перемещаем, используя в функции fseek () позицию конца файла SEEK_END */

void MyRead2()

{ int a[m];

arf= fopen("d:\\ANA\\cpp\\2004_05\\farr2.dat","rb");

for (int i=1; i<=n;i+=2)

{ fseek(arf, -i*sizeof(a),SEEK_END);

fread(a,sizeof(a),1,arf);

printf("\n");

for (int j=0;j<m;j++)

printf("%5d",a[j]);

}

fclose(arf); }

/* Вариант 3. Указатель файла перемещаем, используя в функции fseek () текущую позицию файла SEEK_CUR */

void MyRead3()

{ int a[m];

arf= fopen("d:\\ANA\\cpp\\2004_05\\farr2.dat","rb");

fseek(arf, -1*sizeof(a), SEEK_END);

for (int i=0; i<n/2;i++)

{ fread(a,sizeof(a),1,arf);

printf("\n");

for (int j=0;j<m;j++)

printf("%5d",a[j]);

fseek(arf, -3*sizeof(a),SEEK_CUR);

}

fclose(arf); }

int main()

{ int flag; while (1)

{ cout << "\n1 -- CREATE"<<endl<<

"2 -- READ"<<endl<<

"3 -- Read1"<<endl<<

"4 -- Read2"<<endl<<

"5 -- Read3"<<endl<<

"0 -- EXIT"<<endl;

cin>>flag;

switch (flag)

{ case 1: MyCr(); break;

case 2: MyRead(); break;

case 3: MyRead1(); break;

case 4: MyRead2(); break;

case 5: MyRead3(); break;

case 0: return 0;

}

}

}