Произвольный доступ - SEEK и LSEEK
Нормально при работе с файлами ввод и вывод осуществляется последовательно: при каждом обращении к функциям read и write чтение или запись начинаются с позиции, непосредственно следующей за предыдущей обработанной. Но при необходимости файл может читаться или записываться в любом произвольном порядке. Обращение к системе с помощью функции lseek позволяет передвигаться по файлу, не производя фактического чтения или записи. В результате обращения
lseek(fd,offset,origin);
текущая позиция в файле с дескриптором fd передвигается на позицию offset (смещение), которая отсчитывается от места, указываемого аргументом origin (начало отсчета). Последующее чтение или запись будут теперь начинаться с этой позиции. Аргумент offset имеет тип long; fd и origin имеют тип int. аргумент origin может принимать значения 0,1 или 2, указывая на то, что величина offset должна отсчитываться соответственно от начала файла, от текущей позиции или от конца файла. Например, чтобы дополнить файл, следует перед записью найти его конец:
lseek(fd,0l,2);
чтобы вернуться к началу ("перемотать обратно"), можно написать:
lseek(fd,0l,0);
обратите внимание на аргумент 0l; его можно было бы записать и в виде (long) 0.
функция lseek позволяет обращаться с файлами примерно так же, как с большими массивами, правда ценой более медленного доступа. следующая простая функция, например, считывает любое количество байтов, начиная с произвольного места в файле.
get(fd,pos,buf,n) /*read n bytes from position pos*/ int fd, n; long pos; char *buf; { lseek(fd,pos,0); /*get to pos*/ return(read(fd,buf,n)); }
В более ранних редакциях, чем редакция 7 системы UNIX, основная точка входа в систему ввода-вывода называется seek. функция seek идентична функции lseek, за исключением того, что аргумент offset имеет тип int, а не long. В соответствии с этим, поскольку на PDP-11 целые имеют только 16 битов, аргумент offset, указываемый функции seek, ограничен величиной 65535; по этой причине аргумент origin может иметь значения 3, 4, 5, которые заставляют функцию seek умножить заданное значение offset на 512 (количество байтов в одном физическом блоке) и затем интерпретировать origin, как если это 0, 1 или 2 соответственно. Следовательно, чтобы достичь произвольного места в большом файле, нужно два обращения к seek: сначала одно, которое выделяет нужный блок, а затем второе, где origin имеет значение 1 и которое осуществляет передвижение на желаемый байт внутри блока.
Упражнение 8-2
Очевидно, что seek может быть написана в терминалах lseek и наоборот. напишите каждую функцию через другую.