Программирование на C и C++

Онлайн справочник программиста на C и C++

fseek() и произвольный доступ

Можно выполнять операции произвольного чтения и записи, используя систему буферизированного ввода/вывода, с помощью fseek(), устанавливающей текущую файловую позицию. Она имеет следующий прототип:

int fseek(FILE *fp long нисло_байт, int начало);

где fp - это указатель на файл, возвращенный fopen(), число_байт - это длинное целое, содер­жащее число байт от начала до позиции маркера, а начало - это одно из следующих макроопре­делений (определенных в stdio.h):

Макроопределение

Смысл

SEEK_SET

SEEK_CUR

SEEK_END

Начало файла

Текущая позиция

Конец файла

Макроопределения определены как целочисленные значения, причем SEEK_SET соответствует 0, SEEK_CUR - 1, a SEEK_END - 2. Следовательно, для перехода на число_байт от начала файла следует установить начало в SEEK_SET. Для перехода от текущей позиции надо использо­вать SEEK_CUR, а для перехода от конца файла - SEEK_END. Функция fsee() возвращает 0 в случае удачи или ненулевое значение в случае ошибки.
Например, можно использовать следующий код для чтения 234-го байта файла test:

int func1(void)
{
FILE *fp;
if((fp=fopen("test", "rb")) == NULL){
printf("Cannot open file.");
exit(1);
}
fseek(fp, 234L, O);
return getc(fp); /* чтение одного символа в 234-й позиции */
}
}

Другим примером, использующим функцию fseek(), является следующая программа dump, по­зволяющая просмотреть содержимое, как в ASCII, так и в шестнадцатиричных форматах. Можно смотреть на файл 128-байтными «секторами», причем двигаться можно в произвольном направле­нии. Для выхода из программы следует набрать -1, когда будет предложено ввести номер сектора. Обратим внимание на использование fread() для чтения файла. Если остается прочитать меньше чем SIZE байт, то число, передаваемое в display(), как раз и определяет, сколько символов необхо­димо вывести. (Надо помнить, что fread() возвращает число прочитанных элементов.) Введем про­грамму в компьютер и основательно с ней разберемся:

/* dump: простая дисковая утилита для просмотра, использующая fseek. */
#include <stdio.h>
#include <ctype.h>
#define SIZE 128
void display(int numread);
char buf[SIZE];
void display();
int main(int argc, char *argv[])
{
FILE *fp;
int sector, numread;
if(argc!=2) {
printf("Usage: dump filename");
return 1;
}
if((fp=fopen(argv[1], "rb"))==NULL) {
printf("Cannot open file.");
return 1;
}
do {
printf("Enter sector: ");
scanf("%d", &sector);
if(sector >= 0) {
if(fseek(fp, sector*SIZE, SEEK_SET)) {
printf("seek error");
}
if((numread=fread(buf, 1, SIZE, fp)) != SIZE)
printf("EOF reached.");
display(numread);
}
} while(sector>=0);
return 0;
}

/* вывод содержимого файла */
void display(int numread)
{
int i, j;
for(i=0; i<numread/16; i++) {
for (j=0; j<16; j++) printf("%3X", buf[i*16+j]);
printf(" ");
for(j=0; j<16; j++) {
if(isprint(buf[i*16+j])) printf("%c", buf[i*16+j]);
else printf(".");
}
printf("\n");
}
}

Надо обратить внимание, что библиотечная функция isprint() используется для определения вы­водимых символов. Функция isprint() возвращает истину, если символ можно вывести, и ложь - если нельзя. Для ее использования необходимо подключить заголовочный файл ctype.h. Пример работы dump можно увидеть на рис.

Рисунок: Пример работы дисковой утилиты просмотра