Поблочный и побайтовый режимы управления файлами, страница 5

           long lseek(int fd, long offset, int origin);

Устанавливает текущее положение в файле, чей описатель - fd, по отношению к положению, определяемому значением origin. Последующее чтение или письмо начнется в том положении(позиции), происхождение может быть 0, 1, или 2, чтобы определить, что возмещать, должен быть измерен с начала, от текущего положения(позиции), или с конца файла соответственно. Например, чтобы добавить в конец к файлу (переназначение) в  UNIX, или "a" для fopen, ищут на конец перед записью в файл:

           lseek (fd, 0L, 2);

Вернуться к началу ("перемотка"),

           lseek (fd, 0L, 0);

Заметьте 0L аргумент; это могло бы также быть написано как (long)0 или также, как 0, если lseek должным образом объявлен.

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

Она возвращает число считанных байтов, или -1 на ошибке.

      #include <io.h>

      /* get: read n bytes from position pos */

      int get(int fd, long pos, char *buf, int n)

      {   if (lseek(fd, pos, 0) >> 0) /* get to pos */

                return read ( fd, *buf, n);

           else

                return -1;

      }

Ценность возвращения от lseek длины, которая задает новое положение в файле, или -1, если ошибка происходит. Стандартная функция библиотеки fseek подобна lseek за исключением того, что первый аргумент - FILE *, и возвращаемое значение было бы отлично от нуля, если ошибка произошла.

5.II.5. Пример - Выполнение Fopen и Getc

Позвольте нам иллюстрировать, как некоторые из этих частей взаимодействуют,  показывая выполнение стандартных установившихся практики библиотеки fopen и getc.

Файлы в стандартной библиотеке описаны указателями файла БОЛЕЕ ЧАСТО, чем описателем файла. Указатель файла - указатель на структуру, которая содержит некоторую информацию относительно указателя файла на буфер, так что файл может читаться большими частями; индекс номера знака, оставленного в буфере; указатель на следующий помещаемый в буфер знак; описатель файла; и флаги, описывающие чтение или запись, статус ошибки, и т.д.

Структура данных, которая описывает файл,  содержится в <stdio.h>, который должен быть включен (через #include) в любой исходный файл, который использует установившиеся практику стандартной библиотеки ввода/вывода. Она также включается функциями в этой библиотеке. В следующей выдержке из типичного <stdio.h>, названия(имена), которые предназначены для использования только функциями библиотеки, начинают с подчеркивания, так что с ними столкнуться в программе пользователя менее вероятно. Это соглашение используется всеми стандартными библиотеками.

      #define NULL      0

      #define EOF       (-1)

      #define BUFSIZ    1024

      #define OPEN_MAX 20      /* max #files open at once */

      typedef struct _iobuf {

           int cnt;         /* characters left */

           char *ptr;        /* next character position */

           char *base;       /* location of buffer </

           int flag;        /* mode of file access */

           int fd;          /* file descriptor */

      } FILE;

      extern FILE _iob[OPEN_MAX];

      #define stdin   (&_iob[0])

      #define stdout (&_iob[1])

      #define stderr (&_iob[2])

      enum _flags {

           _READ   = 01,     /* file open for reading */

           _WRITE = 02,     /* file open for writing */

           _UNBUF = 04,     /* file is unbuffered */

           _EOF   = 010,    /* EOF has occurred on this file */

           _ERR   = 020     /* error occurred on this file */

      };

      int _fillbuf (FILE *);

      int _flushbuf (int, FILE *);

      #define feof(p)     (((p)->flag & _EOF) != 0)

      #define ferror(p)   (((p)->flag & _ERR) != 0)

      #define fileno(p)   ((p)->fd)

      #define getc(p)   (--(p)->cnt >= 0 \

           ? (unsigned char) *(p)->ptr++ : _fillbuf(p))

      #define putc(x,p) (--(p)->cnt >= 0 \

           ? *(p)->ptr++ = (x) : _flushbuf ( (x) ,p))

      #define getchar()   getc (stdin)

      #define putchar(x)  putc((x),stdout)

Getc обычно декрементирует индекс, продвигает указатель, и возвращает знак. (вспомните, что long #define продолжен наклонной чертой влево.) Если индекс отрицательныq getc, вызывает функцию _fillbuf, чтобы пополнить буфер, заново инициализировать содержание структуры, и возвращает знак. Знаки возвращены без знака, который гарантирует, что все они всегда положительны.

Хотя мы не будем обсуждать никакие детали, мы включили определение putc, чтобы показать, что он использует тот же самый путь как getc, вызывая функцию _flushbuf, когда буфер полон. Мы также включили macros для вызова по ошибке и статусу конца файла и описателя файла.

Функция fopen может теперь быть написана. fopen получает файла, открывает и помещает его в правильное место, и устанавливает флаги, чтобы указать  надлежащее состояние. fopen не ассигнует(размещает) никакое буферное место; это выполняет _fillbuf, когда файл начинает читаться.

      #include <fcntl.h>

      #include <io.h>

      #define PERMS 0666   /* RW for owner, group, others */

      /* fopen: open file, return file ptr */

      FILE * fopen (char *name, char *mode)

      {     int fd;

           FILE *fp;

           if (*mode != "r'' && *mode != 'w' && *mode != 'a')

                return NULL;

           for (fp = _iob; fp < _iob + OPEN_MAX; fp++)