Linux программирование в примерах | страница 85



Смысл значений и их действие на положение в файле показаны на рис. 4.1. При условии, что файл содержит 3000 байтов и что перед каждым вызовом >lseek() текущим является смещение 2000 байтов, новое положение после каждого вызова будет следующим.

Рис. 4.1. Смещения для >lseek()

Отрицательные смещения относительно начала файла бессмысленны; они вызывают ошибку «недействительный параметр».

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

>off_t curpos;

>...

>curpos = lseek(fd, (off_t)0, SEEK_CUR);

Буква >l в >lseek() означает >long. >lseek() был введен в V7 Unix, когда размеры файлов были увеличены; в V6 был простой системный вызов >seek(). В результате большое количество старой документации (и кода) рассматривает параметр offset как имеющий тип >long, и вместо приведения к типу >off_t довольно часто можно видеть суффикс L в константных значениях смешений:

>curpos = lseek(fd, 0L, SEEK_CUR);

На системах с компилятором стандартного С, где >lseek() объявлена с прототипом, такой старый код продолжает работать, поскольку компилятор автоматически преобразует 0L из >long в >off_t, если это различные типы.

Одной интересной и важной особенностью >lseek() является то, что она способна устанавливать смещение за концом файла. Любые данные, которые впоследствии записываются в это место, попадают в файл, но с образованием «интервала» или «дыры» между концом предыдущих данных файла и началом новых данных. Данные в промежутке читаются, как если бы они содержали все нули.

Следующая программа демонстрирует создание дыр. Она записывает три экземпляра >struct в начало, середину и дальний конец файла. Выбранные смешения (строки 16–18, третий элемент каждой структуры) произвольны, но достаточно большие для демонстрации особенности:

>1  /* ch04-holes.c --- Демонстрация lseek() и дыр в файлах. */

>2

>3  #include /* для fprintf(), stderr, BUFSIZ */

>4  #include /* объявление errno */

>5  #include /* для flags для open() */

>6  #include /* объявление strerror() */

>7  #include /* для ssize_t */

>8  #include /* для off_t, etc. */

>9  #include   /* для mode_t */

>10

>11 struct person {

>12  char name[10]; /* имя */

>13  char id[10]; /* идентификатор */

>14  off_t pos; /* положение в файле для демонстрации */

>15 } people[] = {

>16  { "arnold", "123456789", 0 },

>17  { "miriam", "987654321", 10240 },