Здравствуйте, уважаемые подписчики! Мы продолжаем изучать низкоуровневый ввод-вывод в Linux и сегодня поговорим о перемещении внутри файла.
1. Позиции
1.1. Основные понятия
Каждый раз открывая файл, вы попадаете в начальную позицию. Иными словами, первая операция чтения/записи будет обращена к началу файла. То есть ваша текущая позиция совпадает с началом файла. Каждый прочитанный системным вызовом read() или записанный системным вызовом write() байт перемещает текущую позицию вперед. Текущая позиция открытого файла находится в специальной таблице ядра, на которую указывает дескриптор файла. Если текущая позиция при чтении совпадает с концом файла, то файл счтитается полностью
прочитанным. Если файл находится, например, на диске, то драйвер устройства избавляет вас от надобности постоянно контролировать позиции чтения/записи. Однако иногда требуется взять контроль в свои руки. Представьте себе, что вам надо дважды повторить побайтовое чтение файла. Если бы мы не имели возможности менять текущую позицию открытого файла, нам пришлось бы сначала закрыть файл, а затем опять открыть тот же файл. Идеология Unix не терпит таких трюков!
1.2. Смещение позиции
Возникает вопрос: куда можно переместить текущую позицию? Прежде чем ответить на это вопрос, давайте рассмотрим общепринятое соглашение по обозначению позиций. Существуют три константы:
SEEK_SET - начало файла
SEEK_CUR - текущая позиция
SEEK_END - конец файла
Перемещаясь по файлу обычно используется следующий формат записи:
КОНСТАНТА +/- СМЕЩЕНИЕ
В качестве смещения может выступать любое целое знаковое число. Рассмотрим несколько примеров:
SEEK_CUR - 1 - предыдущий байт
SEEK_SET + 20 - 20-й байт от начала файла
SEEK_END - 2 - предпоследний байт в файле
SEEK_CUR + 1 - следующий байт после конца файла (для записи)
В Linux для обозначения позиций используется специальный тип off_t, объявленный в заголовочном файле sys/types.h.
1.3. Системный вызов lseek()
Системный вызов lseek() позволяет перемещаться на указанную позицию в файле. Если перемещение прошло успешно, то возвращается новая текущая позиция, в случае ошибки возвращается отрицательное значение. Отрицательное значение, например, может быть возвращено, если применить к SEEK_SET отрицательное смещение. lseek() принимает три аргумента: дескриптор файла, позицию отсчета (одну из вышеупомянутых костант) и смещение:
off_t lseek (ДЕСКРИПТОР, СМЕЩЕНИЕ, ПОЗИЦИЯ);
Рассмотрим несколько примеров:
lseek (fd, 20, SEEK_CUR); - "перепрыгивает" на 20 байт вперед от текущей позиции.
lseek (fd, 64, SEEK_SET); - "перепрыгивает" на 64-й байт в файле.
lseek (fd, -2, SEEK_END); - "перепрыгивает" на предпоследний байт в файле.
2. Пример
В качестве примера рассмотрим простую программу, которая дважды читает один и тот же файл и выводит его на экран.
В следующем выпуске рассылки мы рассмотрим некоторые тонкости низкоуровневого ввода-вывода, а также познакомимся с несколькими новыми системными вызовами. Поздравляю прекрасную половину человечества с праздником 8 марта!
Если возникнут вопросы, направляйте их в форум на Lindevel.Ru (http://www.lindevel.ru) или на e-mail: nn@lindevel.ru. Спасибо за внимание!