Основные приемы работы с файлами
Буферная переменная
Мы знаем, что для чтения компоненты файла используется процедура READ(F,V). По этой процедуре выполняются два действия:
1. Копирование компоненты файла F, на которую смотрит окно, и присваивание этого значения переменной V.
2. Перемещение окна на следующую компоненту.
Однако, иногда удобно эти два действия разделить. Для этого вводится понятие буферной переменной. Она имеет имя: F^. Эту переменную не надо описывать, она определяется автоматически, как только описывается файл F. Тип F^ совпадает с типом компоненты файла. С переменной F^ можно выполнять все действия, как над данными типа компонент файла.
Если выполнена процедура RESET(F), то происходит установка окна на первую компоненту и значение этой компоненты идет в F^:
F | X | F^ | ||||||||||||||
^ | ||||||||||||||||
окно | ||||||||||||||||
Если выполнен RESET(F), а файл F пуст, т.е. EOF(F)=TRUE, то значение F^ неопределенно. Окно файла указывает на его конец.
Для передвижения окна файла и заполнения (чтения) буферной переменной используются в некоторых версиях Паскаля специальные процедуры-операторы GET и PUT:
a. GET(F) - передвижение окна на следующую компоненту и засылка значения этой компоненты в переменную F^.
F^ | f | ||||||||||||
^ | |||||||||||||
окно | |||||||||||||
после GET(F):
F^ | f | |||||||
^ | ||||||||
окно |
b. PUT(F) - запись в файл значения F^ и сдвиг вправо. Здесь до PUT(F) надо F^ присвоить очередное значение. В режиме записи значений в файл F^ служит поставщиком значений компонент. После процедуры REWRITE(F) окно устанавливается на первую компоненту, значение F^ не определено. Затем надо определить значение F^ с помощью команды присваивания: F^:=3. Если теперь написать процедуру PUT(F), то значение F^ идет в компоненту, где стоит окно, после чего значение F^ становится неопределенным:
F^ | f | ||||||||
^ | |||||||||
окно |
PUT(F)
F^ | f | |||||||||
^ | ||||||||||
окно |
Пример 2. Запись чисел v1 - v5 в файл BUFFER и последующий
их вывод на печать
program KVADRKOREN;
var R: real; I: integer; BUFFER: file of real;
begin
rewrite(BUFFER);
for I:=1 to 5 do
begin
BUFFER^:=sqrt(I); put(BUFFER);
end;
reset(BUFFER);
for I:=1 to 5 do
begin
R:=BUFFER^;
get(BUFFER); writeln(R);
end;
end.
Замечание. В некоторых версиях процедуры GET и PUT не существуют (в частности, это имеет место для Турбо-Паскаля). Но без них можно обойтись, т.к. существуют эквивалентные им операторы READ и WRITE. Им эквивалентны следующие составные операторы:
READ(F,V) => BEGIN V:=F^; GET(F) END;
WRITE(S,W) => BEGIN S^:=W; PUT(S) END.
Известно существование многих версий Паскаля, каждая из которых имеет свои особенности и отличия от стандарта Паскаля. Рассмотрим некоторые приемы работы с файлами в системах Turbo-Pascal для ПЭВМ "Ямаха" и IBM PC.
1. В этой версии Паскаля не существует операторов GET и PUT, поэтому вся работа с файлами идет на уровне рассмотренных выше операторов.
2. Перед началом работы с файлами (до первого обращения к файлу) должна быть выполнена процедура ASSIGN. Эта процедура отождествляет имя файла с соответствующей файловой переменной.
СИНТАКСИС: assign(var F: file; NAME: string), где NAME - имя файла на диске, F - имя файловой переменной.
После выполнения этой процедуры NAME и F отождествляются, например, ASSIGN(F,'nomfile') отождествляет файловую переменную F с его именем на диске. В качестве имени файла может быть указаноего полное имя, т.е. путь к этому файлу, например:
ASSIGN(F,'С:\WORK\ MIM\nomfile').
3. После окончания работы с файлом он должен быть закрыт процедурой CLOSE, иначе результат может быть потерян, т.к. директория не будет обновлена.
СИНТАКСИС: CLOSE(var F:file), где F - имя файловой переменной.
Процедуры ASSIGN и CLOSE взаимосвязаны и работают в паре друг с другом. Как уже сказано выше, перед началом работы с файлом выполняется процедура ASSIGN(F, 'nomfile'), которая для логического файла F готовит (ищет) на диске в указанной директории файл с именем NOMFILE. При окончании работы с файлом по выполнению процедуры CLOSE происходит его обновление (в случае записи) и закрытие (в случае чтения).
4. В программе надо уметь задавать исходные файлы. Эти файлы надо делать в цикле, используя при этом формирование компонент, либо в форме некоторого выражения по RANDOMIZE, либо задействовать обычную команду READ для ввода данных с клавиатуры. Цикл можно делать FOR, если формирование файла идет по RANDOMIZE, или WHILE (REPEAT), если файл формируется по признаку конца ввода.
Напомним, что RANDOMIZE - процедура инициализации генератора случайных величин; RANDOM - функция генерации случайных чисел.
Рассмотрим все эти особенности на примере формирования, обработки и вывода файлов.
ПРИМЕР 2. Для двух целочисленных файлов F и G одинаковой длины образовать третий целочисленный файл H, компоненты которого определяются по правилу: Hi=MAX{Fi,Gi}. В программе предусмотреть вывод на экран все трех файлов
program MAXELEM;
type FT = file of integer;
var F,G,H: FT;
I,J: integer;
procedure VIVODFILE(var A:FT);
begin
reset(A);
while not eof(A) do
begin
read(A,I); write(I:4);
end; writeln;
end;
begin { формирование исходных файлов }
assign(F,'F'); assign(G,'G');
randomize; rewrite(F); rewrite(G);
for I:=1 to 10 do
begin
J:= random(10)-5; write(F,J);
J:= random(10)-5; write(G,J);
end;
VIVODFILE(F); close(F);
VIVODFILE(G); close(G);
assign(H,'H');
{ формирование файла результата }
reset(F); reset(G); rewrite(H);
while not eof(F) do
begin
read(F,I); read(G,J);
if I > J then write(H,I) else write(H,J);
end; VIVODFILE(H);
close(H);
end.
5. Файл в данный момент времени открыт либо для чтения, либо для записи. Поэтому для добавления к файлу новых элементов необходимо сначала переписать во вспомогательный файл исходный, затем добавить к нему новые элементы. При этих двух операциях вспомогательный файл открыт для чтения. После заполнения вспомогательного файла он переписывается в исходный, при этом начальные элементы исходного файла заносятся туда во второй раз. Все эти операции представлены в виде следующей процедуры:
procedure DOBAVLENIE(N: integer; var A:file);
var B: file; I,J: integer;
begin
{ Запись файла А в файл B }
assign(B,'B');reset(A; rewrite(B);
while not eof(A) do
begin read(A,I); write(B,I); end;
{ Добавление новых элементов в файл B }
for I:=1 to n do
begin
J:= random(10)-5; write(B,J);
end;
{ Запись файла B в файл A }
rewrite(A); reset(B);
while not eof(B) do
begin read(B,I); write(A,I); end;
end.