Позиционирование
Управляя содержимым файлового указателя позиции, программа может произвольно считывать или перезаписывать различные участки файла, то есть организовать прямой доступ к содержимому файла. Прямой доступ к файлу может вам понадобится, например, для создания систем управления базами данных.
Установить файловый указатель в нужную вам позицию можно с помощью функции 42h прерывания
INT21h MS-DOS:
На входе: | AH = 42h |
AL = метод кодирования: 00h абсолютное смещение от начала файла 01h смещение от текущей позиции 02h смещение от конца файла |
|
BX = файловый индекс открытого файла | |
CX = старший байт смещения | |
DX = младший байт смещения | |
На выходе: | AX = Код ошибки, если был установлен в 1
флаг переноса CF; Младший байт текущей позиции, если флаг переноса CF сброшен в 0. |
DX = Старший байт текущей позиции |
Функция позволяет указывать новое значение указателя либо как абсолютное смещение от начала файла, либо как смещение от текущей позиции, либо как смещение от конца файла. В последних двух случаях используется смещение со знаком. Для указания смещения или абсолютной позиции программа должна задать в регистрах CX, DX
32-битовое значение.
Если использовать метод кодирования 02h и задать нулевое смещение, функция установит указатель на конец файла. Это обстоятельство может быть использовано для определения размера файла в байтах.
Что произойдет, если при использовании методов кодирования 01h или 02h попытаться установить указатель позиции до начала файла?
Функция 42h при этом не возвратит признак ошибки, однако если будет сделана попытка прочитать или записать данные, то соответствующая функция чтения/записи завершится с ошибкой.
Стандартные библиотеки трансляторов Microsoft QC 2.5 и C 6.0 содержат функции, предназначенные для управления содержимым файлового указателя позиции и получения текущего значения этого указателя. Это функции lseek(), tell(), filelength().
Функция lseek() работает аналогично только что описанной функции 42h. Приведем ее прототип:
long lseek( int handle, long offset, int origin);
Первый параметр определяет файл, для которого выполняется операция позиционирования. Параметр offset определяет смещение. Последний параметр задает метод кодирования смещения. Он может принимать следующие значения, описанные в фале stdio.h:
SEEK_SET | Абсолютное смещение от начала файла |
SEEK_CUR | Смещение относительно текущей позиции |
SEEK_END | Смещение относительно конца файла |
Вы, конечно, можете использовать функцию lseek()
для определения размера файла или текущей файловой позиции. Однако для того, чтобы узнать размер файла, лучше воспользоваться специальной функцией filelength():
long filelength(int handle);
Функция возвращает размер файла в байтах. Файл задается параметром handle. В случае ошибки функция возвращает значение -1L.
Для того, чтобы определить текущую файловую позицию, можно использовать функцию tell():
long tell(int handle);
Эта функция возвращает текущую позицию для файла, определенного параметром handle, или -1L, в случае ошибки.
Для демонстрации использования функций позиционирования приведем простую программу, которая для заданного файла и позиции внутри файла отображает содержимое одного байта. Дополнительно программа определяет размер файла и текущую позицию после чтения байта.
#include <io.h> #include <stdio.h> #include <fcntl.h>
void main(void); void main(void) {
int handle; long position, length; char buffer[2], fname[80];
// Запрашиваем имя файла, с которым будем работать
printf("Введите имя файла: "); gets(fname);
// Открываем файл
handle = open(fname, O_BINARY | O_RDONLY);
// Если такого файла нет, выводим сообщение об ошибке // и завершаем работу программы
if(handle == -1) { printf("\nНет такого файла!"); exit(-1); }
// Определяем и выводим на экран размер файла в байтах
length = filelength(handle);
printf("\nДлина файла %s составляет %ld байтов\n", fname, length);
// Запрашиваем позицию для чтения и отображения байта
do {
printf("Введите позицию: "); scanf("%ld", &position);
} while(position > length);
// Устанавливаем заданную позицию
lseek(handle, position, SEEK_SET);
// Читаем один байт в буфер, начиная с установленной // позиции
if(read(handle, buffer, 1) == -1) {
// Для вывода сообщения об ошибке используем функцию perror(), // которая добавляет к сообщению, заданному в параметре, // расшифрованное системное сообщение об ошибке. // Код ошибки функция perror() берет из переменной errno.
perror("Ошибка при чтении"); exit(-1); }
// Выводим считанный байт на экран
printf( "Смещение: %ld; байт: %02.2x ('%c')\n", position, (unsigned char)*buffer, *buffer);
// Определяем текущую позицию и выводим ее // на экран
position = tell(handle); printf("\nТекущая позиция в файле: %ld\n", position);
// Закрываем файл
close(handle); }