13.4.2. Игнорирование указателя файла

13.4.2. Игнорирование указателя файла

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

lseek(fd, SEEK_SET, offset1);

read(fd, buffer, bufferSize);

offset2 = someOperation(buffer);

lseek(fd, SEEK_SET, offset2);

read(fd, buffer2, bufferSize2);

offset3 = someOperation(buffer2);

lseek(fd, SEEK_SET, offset3);

read(fd, buffer3, bufferSize3);

Необходимость поиска нового расположения с помощью lseek() перед каждым read() удваивает количество системных вызовов, поскольку указатель файла никогда не располагается правильно после read() из-за непоследовательной природы хранения данных в файле. Существуют альтернативы read() и write(), принимающие смещение файла в качестве параметра, и ни одна из альтернатив не использует указатель файла, чтобы выяснить, к какой части файла можно получить доступ, или какую его часть можно обновить. Обе функции работают только применительно к просматриваемым файлам, поскольку непросматриваемые файлы можно читать или записывать только в текущем расположении.

#define XOPEN_SOURCE 500

#include <unistd.h>

size_tpread(int fd, void * buf, size_t count, off_t offset);

size_t pwrite(int fd, void * buf, size_t count, off_t offset);

#endif

Это выглядит подобно прототипам read() и write() с четвертым параметром, offset. offset определяет, с какой точки файла следует читать, а в какую — записывать. Как и их "тезки", эти функции возвращают количество переданных байтов. Ниже приведена версия pread(), реализованная с помощью read() и lseek(), что облегчает понимание ее функции[99].

int pread (int fd, void * data, int size, int offset) {

 int oldOffset;

 int rc;

 int oldErrno;

 /* переместить указатель файла в новое расположение */

 oldOffset = lseek(fd, SEEK_SET, offset);

 if (oldOffset < 0) return -1;

 rc = read(fd, data, size);

 /* восстановить указатель файла, предварительно сохранив errno */

 oldErrno = errno;

 lseek(fd, SEEK_SET, oldOffset);

 errno = oldErrno;

 return rc;

}