Linux программирование в примерах
int whenceОписывает положение в файле, относительно которого отсчитывается
. См. табл. 4.4.offsetТаблица 4.4. Значения
дляwhencelseek()
Именованная константа Значение Комментарий SEEK_SET0 абсолютно, т.е. относительно начала файлаoffsetSEEK_CUR1 относительно текущей позиции в файлеoffsetSEEK_END2 относительно конца файла.offsetБольшое количество старого кода использует числовые значения, приведенные в табл. 4.4. Однако, любой новый код, который вы пишете, должен использовать символические имена, значение которых более ясно.
Смысл значений и их действие на положение в файле показаны на рис. 4.1. При условии, что файл содержит 3000 байтов и что перед каждым вызовом
текущим является смещение 2000 байтов, новое положение после каждого вызова будет следующим.lseek()Рис. 4.1. Смещения для
lseek()Отрицательные смещения относительно начала файла бессмысленны; они вызывают ошибку «недействительный параметр».
Возвращаемое значение является новым положением в файле. Поэтому, чтобы получить ваше текущее местоположение в файле, используйте
off_t curpos;...curpos = lseek(fd, (off_t)0, SEEK_CUR);Буква
вlозначаетlseek().longбыл введен в V7 Unix, когда размеры файлов были увеличены; в V6 был простой системный вызовlseek(). В результате большое количество старой документации (и кода) рассматривает параметр offset как имеющий типseek(), и вместо приведения к типуlongдовольно часто можно видеть суффикс L в константных значениях смешений:off_tcurpos = lseek(fd, 0L, SEEK_CUR);На системах с компилятором стандартного С, где
объявлена с прототипом, такой старый код продолжает работать, поскольку компилятор автоматически преобразует 0L изlseek()вlong, если это различные типы.off_tОдной интересной и важной особенностью
является то, что она способна устанавливать смещение за концом файла. Любые данные, которые впоследствии записываются в это место, попадают в файл, но с образованием «интервала» или «дыры» между концом предыдущих данных файла и началом новых данных. Данные в промежутке читаются, как если бы они содержали все нули.lseek()Следующая программа демонстрирует создание дыр. Она записывает три экземпляра
в начало, середину и дальний конец файла. Выбранные смешения (строки 16–18, третий элемент каждой структуры) произвольны, но достаточно большие для демонстрации особенности:struct1 /* ch04-holes.c --- Демонстрация lseek() и дыр в файлах. */23 #include <stdio.h> /* для fprintf(), stderr, BUFSIZ */4 #include <errno.h> /* объявление errno */5 #include <fcntl.h> /* для flags для open() */6 #include <string.h> /* объявление strerror() */7 #include <unistd.h> /* для ssize_t */8 #include <sys/types.h> /* для off_t, etc. */9 #include <sys/stat.h> /* для mode_t */1011 struct person {12 char name[10]; /* имя */13 char id[10]; /* идентификатор */14 off_t pos; /* положение в файле для демонстрации */15 } people[] = {16 { "arnold", "123456789", 0 },17 { "miriam", "987654321", 10240 },18 { "joe", "192837465", 81920 },19 };2021 int22 main(int argc, char **argv)23 {24 int fd;25 int i, j;2627 if (argc < 2) {28 fprintf(stderr, "usage: %s file\n", argv[0]);29 return 1;30 }3132 fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, 0666);33 if (fd < 0) {34 fprintf(stderr, "%s: %s: cannot open for read/write: %s\n",35 argv[0], argv[1], strerror(errno));36 return 1;37 }3839 j = sizeof(people) / sizeof(people[0]); /* число элементов */Строки 27–30 гарантируют, что программа была вызвана правильно. Строки 32–37 открывают именованный файл и проверяют успешность открытия.
Вычисление числа элементов
массива в строке 39 использует отличный переносимый трюк число элементов является размером всего массива, поделенного на размер первого элемента. Красота этого способа в том, что он всегда верен: неважно, сколько элементов вы добавляете в массив или удаляете из него, компилятор это выяснит. Он не требует также завершающей сигнальной метки; т.е. элемента, в котором все поля содержат нули,jили т.п.NULL
