Если не выполнялись специальные действия, операции чтения и записи обращаются к последовательным байтам в файле. Позиция в файле для следующей операции чтения или записи хранится во внутреннем указателе — поле в структуре FILE, автоматически устанавливаемом и изменяемом стандартными функциями ввода-вывода. Однако можно изменить место следующего чтения или записи, используя функцию fseek(), модифицирующую внутренний указатель.
Объявление прототипа функции fseek():
int fseek(FILE *stream, long offset, int ptrname)
Это объявление находится в файле заголовков stdio.h, поэтому программы, использующие эту функцию, должны включать следующую директиву препроцессора:
#include <stdio.h>
Функция fseek() — стандартная функция языка Си, устанавливает позицию в потоке stream для следующей операции чтения-записи на расстоянии offset байтов от позиции ptrname, принимающей следующие значения:
Функция fseek() возвращает ненулевое значение для недопустимых установок, 0 в противном случае.
Пример 1
fseek(fp, 0L, 0); /*установка в начало*/
fseek(fp, 0L, 2); /*в конец файла*/
fseek(fp, -sizeof(struct emp), 1); /*возврат на одну структуру*/
Для реализации произвольного доступа к файлу бывает полезна функция ftell().
Объявление прототипа функции ftell():
long ftell(FILE *stream)
Функция ftell() — стандартная функция языка Си, которая возвращает смещение текущей позиции внутреннего указателя относительно начала файла (например, 0, если он указывает на начало файла). Для компилятора языка Си в ОС UNIX это смещение измеряется в байтах, для других операционных систем это может быть не так.
Пример 2
/*Печатает хранящуюся информацию о запрошенном объекте*/
#include <stdio.h>
struct part_info {
                 char desc[20];
                 int qty;
                 int cost;
                 }part;
int main()
{
  FILE *rptr;
  long x;

  if ((rptr=fopen("p_data","r"))==NULL)
    {
    fprintf(stderr,"Файл данных не может быть открыт\n");
    exit(1);
    }
  printf("Введите порядковый номер записи:");
  scanf("%ld", &x);
  fseek(rptr, ((x-1)*sizeof(part)), 0);
  fread (&part, sizeof(part), 1, rptr);
  printf("%s\t%d\t%d\n", part.desc, part.qty, part.cost);
}
Произвольный доступ при обновлении файла
Файл может использоваться как для чтения так и для записи, если он открыт для "обновления" ("r+", "w+", "a+"). В этом случае используется лишь один буфер, который должен вытесняться на диск между выполнением операций чтения и записи для обеспечения требуемой взаимной последовательности считываемых и записываемых данных. Для этого необходимо или явно вызывать функцию fflush(), или использовать функцию fseek(), которая, кроме установки позиции в файле для следующего чтения или записи, вызывает функцию fflush() для вытеснения буфера.
Пример 3
#include <stdio.h>
...
if ((rptr=fopen("p_data","r+")) == (FILE *)NULL)
  {
   fprintf(stderr,"Файл данных не может быть открыт\n");
   exit(1);
  }
/*изменяет все поля cost в учетном файле, составленном из структур*/
while (fread(&part, sizeof(part), 1, fp) != 0)
  {
   part.cost *= 1.07;
   fseek(fp, -sizeof(part), 1);
   /*на одну запись назад*/
   fwrite(&part, sizeof(part), 1, fp);
   fseek(fp, 0L, 1);
/* вытесняет буфер перед следующим чтением */
}
...