Записи. Бинарные файлы
Описание типизированных файлов
В разделе var файловые переменные, предназначенные для работы с типизированными файлами, описываются следующим образом:
var <файловая_перем>: file of <тип_элементов_файла>;
Никакая файловая переменная не может быть задана константой.
Назначение типизированного файла
С этого момента и до конца раздела под словом "файл" мы будем подразумевать " бинарный типизированный файл " (разумеется, если специально не оговорено иное).
Команда assign(f,'<имя_файла>'); служит для установления связи между файловой переменной f и именем того файла, за работу с которым эта переменная будет отвечать.
Строка ' <имя_файла> ' может содержать полный путь к файлу. Если путь не указан, файл считается расположенным в той же директории, что и исполняемый модуль программы.
Открытие и закрытие типизированного файла
В зависимости от того, какие действия ваша программа собирается производить с открываемым файлом, возможно двоякое его открытие:
reset(f); - открытие файла для считывания из него информации и одновременно для записи в него (если такого файла не существует, попытка открытия вызовет ошибку). Эта же команда служит для возвращения указателя на начало файла;
rewrite(f); - открытие файла для записи в него информации; если такого файла не существует, он будет создан; если файл с таким именем уже есть, вся содержавшаяся в нем ранее информация исчезнет.
Закрываются типизированные файлы процедурой close(f), общей для всех типов файлов.
Считывание из типизированного файла
Чтение из файла, открытого для считывания, производится с помощью команды read(). В скобках сначала указывается имя файловой переменной, а затем - список ввода1См. лекцию 1.:
read(f,a,b,c); - читать из файла f три однотипные переменные a, b и c.
Вводить из файла можно только переменные соответствующего объявлению типа, но этот тип данных может быть и структурированным. Cкажем, если вернуться к примеру, приведенному в начале п. " Типизированные файлы ", то станет очевидным, что использование типизированного файла вместо текстового позволит значительно сократить текст программы:
type toy = record name: string[20]; price: real; age: set of 0..18; {задано границами} end; var f: file of toy; a: array[1..100] of toy; begin assign(f,input); reset(f); for i:=1 to 100 do if not eof(f) then read(f,a[i]); close(f); ... end.
Поиск в типизированном файле
Уже знакомая нам функция eof(f:file):boolean сообщает о достигнутом конце файла. Все остальные функции "поиска конца" ( eoln(), seekeof() и seekeoln() ), свойственные текстовым файлам, нельзя применять к файлам типизированным.
Зато существуют специальные подпрограммы, которые позволяют работать с типизированными файлами как со структурами прямого доступа:
- Функция filepos(f:file):longint сообщит текущее положение указателя в файле f. Если он указывает на самый конец файла, содержащего N элементов, то эта функция выдаст результат N. Это легко объяснимо: элементы файла нумеруются начиная с нуля, поэтому последний элемент имеет номер N-1. А номер N принадлежит, таким образом, "несуществующему" элементу - признаку конца файла.
- Функция filesize(f:file):longint вычислит длину файла f.
- Процедура seek(f:file,n:longint) передвинет указатель в файле f на начало записи с номером N. Если окажется, что n больше фактической длины файла, то указатель будет передвинут и за реальный конец файла.
- Процедура truncate(f:file) обрежет "хвост" файла f: все элементы начиная с текущего и до конца файла будут из него удалены. На самом же деле произойдет лишь переписывание признака "конец файла" в то место, куда указывал указатель, а физически "отрезанные" значения останутся на прежних местах - просто они станут "бесхозными".
Запись в типизированный файл
Сохранять переменные в файл, открытый для записи, можно при помощи команды write(). Так же как и в случае считывания, первой указывается файловая переменная, а за ней - список вывода:
write(f,a,b,c); - записать в файл f (предварительно открытый для записи командами rewrite(f) или reset(f) ) переменные a, b, c.
Выводить в типизированный файл можно только переменные соответствующего описанию типа данных. Неименованные и нетипизированные константы нельзя выводить в типизированный файл.
Типизированные файлы рассматриваются как структуры одновременно и прямого, и последовательного доступа. Это означает, что запись возможна не только в самый конец файла, но и в любой другой его элемент. Записываемое значение заместит предыдущее значение в этом элементе (старое значение будет "затерто").
Например, если нужно заместить пятый элемент файла значением, хранящимся в переменной а, то следует написать следующий отрывок программы:
seek(f,5); {указатель будет установлен на начало 5-го элемента}
write(f,a); {указатель будет установлен на начало 6-го элемента}
Замечание: Поскольку и чтение из файла, и запись в файл сдвигают указатель на следующую позицию, то в случае, когда необходимо сначала прочитать значение, хранящееся в каком-то элементе, а затем вписать на это место новые данные, необходимо производить поиск дважды:
seek(f,5); {указатель - на начало 5-го элемента}
read(f,a); {указатель - на начало 6-го элемента}
seek(f,5); {указатель - на начало 5-го элемента}
write(f,b); {указатель - на начало 6-го элемента}
А что произойдет, если в файле содержится всего N элементов, а запись производится в ( N+k )-й? Тогда начало файла останется прежним, затем в файл будет включен весь тот "мусор", что оказался между его концом и записываемой переменной, и, наконец, последним элементом нового файла станет записанное значение.