Позиционирование в потоке.В начале главы были рассмотрены посимвольный, построчный и форматный обмены с файлами, организованными в виде потока байтов. Эти средства позволяли записать в файл данные и читать из него информацию только последовательно.
Операция чтения (или записи) для потока всегда производится, начиная с текущей позиции в потоке. Начальная позиция чтения/записи в потоке устанавливается при открытии потока и может соответствовать начальному или конечному байту потока в зависимости от режима открытия потока. При открытии потока в режимах "r" и "w" указатель текущей позиции чтения/записи в потоке устанавливается на начальный байт потока, а при открытии в режиме "а" - в конец файла (за конечным байтом). При выполнении каждой операции ввода-вывода указатель текущей позиции в потоке перемещается на новую текущую позицию в соответствии с числом прочитанных (записанных) байтов.
Рассмотрим средства позиционирования в потоке, позволяющие перемещать указатель (индикатор) текущей позиции в потоке на нужный байт. Эти средства дают возможность работать с файлом на диске, как с обычным массивом, осуществляя доступ к содержимому файла в произвольном порядке.
В библиотеку языка Си включена функция fseek( )для перемещения (установки) указателя текущей позиции в потоке на нужный байт потока (файла). Она имеет следующий прототип:
int fseek(указатель_напоток, смещение, начало_отсчета);
Смещение задается переменной или выражением типа longи может быть отрицательным, т.е. возможно перемещение по файлу в прямом и обратном направлениях. Начало отсчета задается одной из предопределенных констант, размещенных в заголовочном файле stdio.h:
SEEK_SET(имеет значение 0) - начало файла;
SEEK_CUR(имеет значение 1) -текущая позиция;
SEEK_END(имеет значение 2) - конец файла.
Здесь следует напомнить некоторые особенности данных типа long.Этот тип определяется для целочисленных констант и переменных, которым в памяти должно быть выделено больше места, чем данным типа int.Обычно переменной типа longвыделяется 4 байта, чем и определен диапазон ее значений. Описание данных типа long:
Константа типа longзаписывается в виде последовательности десятичных цифр, вслед за которыми добавляется разделитель L или 1. Примеры констант типа long:
331
В текстах программ лучше использовать L, чтобы не путать I с цифрой 1.
Функция fseek( ) возвращает 0, если перемещение в потоке (файле) выполнено успешно, в противном случае возвращается ненулевое значение.
Приведем примеры использования функции fseek( ). Перемещение к началу потока (файла) из произвольной позиции:
Перемещение к концу потока (файла) из произвольной позиции:
В обоих примерах смещение задано явно в виде нулевой десятичной константы 0L типа long.
При использовании сложных типов данных (таких, как структура) можно перемещаться в потоке (файле) на то количество байтов, которое занимает этот тип данных. Пусть, например, определена структура:
Тогда при следующем обращении к функции fseek( ) указатель текущей позиции в потоке будет перемещен на одну структуру назад относительно текущей позиции:
Для иллюстрации работы с файлом в режиме произвольного доступа рассмотрим пример небольшого трехъязычного словаря, содержащего названия цифр от 1 до 9 на английском, немецком и французском языках. Для обслуживания словаря необходимы 2 программы: программа загрузки словаря в файл на диске и программа поиска слова в словаре (в ней используется функция fseek( ) ).
"База данных" словаря организована в файле vac.dat. Функция загрузки запрашивает названия для цифр от 1 до 9. Названия конкретной цифры (в предположении, что каждое название не превышает 9 букв) на всех трех языках записываются в одной строке через пробелы. Сформированная строка по нажатию клавиши <Enter> прочитывается в массив символов buf[ ]. Текст программы:
Введенные данные (представление цифры в формате целого числа и названия цифр на трех языках) побайтно выводятся в файл vac.dat, образуя в нем "записи", структура которых показана на рис. 7.2.
Рис.7.2. Состав записи "Цифра"
Следующая программа перевода (trans) запрашивает сначала язык, на котором нужно выводить названия цифр, а затем в цикле запрашиваются цифры. Язык идентифицируется первой буквой своего русского наименования: 'а' или 'А' - для английского; 'н' или 'Н' - для немецкого; 'ф' или 'Ф' - для французского. Признаком завершения программы служит ввод цифры 0. Текст программы trans:
При вычислении позиции (pos) в файле, с которой начинается строка перевода, участвуют следующие составляющие:
k-1 - выбирает подстроку (длиной 32 байта), в которой содержится перевод;
2 - учитывает длину поля цифры (2 байта);
lang*10 - задает смещение до требуемого значения цифры в подстроке перевода.
На рис. 7.3 показаны составляющие смещения для искомого поля с переводом на немецкий язык.
Рис. 7.3. Составляющие смещения для записей в файле словаря
Предлагаем самостоятельно разработать функцию поиска в файле заданной подстроки и на ее основе написать программу перевода названий цифр с одного языка на другой. В табл. 7.3 приводятся названия цифр от 1 до 9 на трех языках.