Типизированный файл состоит из последовательности однотипных или одинаковых компонент и может содержать различное их число (возможно ни одной).
Тип компонент файла практически любой, но он не должен содержать внутри себя других файлов. Определяются файловые переменные следующим образом:
<список идентификаторов файловых переменных>:
File of <тип компонентов файла>;
Примеры:
var
fl : File of Byte;
f2 : File of Char;
f3, f4 : File of Integer;
f5 : File of Real;
f6 : File of array [1..3] of real;
Здесь f1, f2, f3, f4, f5 – файловые переменные, описывающие файлы, компоненты которых – простые типы; f6 – файловая переменная файла, у которого каждая компонента – массив из 3-х вещественных чисел типа real.
Файловая переменная связывается с именем файла на логическом диске. Для этого используют следующую процедуру Assign с двумя параметрами:
Assign ( fl, S);
Здесь fl- файловая переменная, передаваемая по ссылке;
S — путь и/или полное имя файла.
Примеры:
assign(fl, 'с:\turbo\bgi\bgi.scr');
assign(fl, 'c:\arm.txt');
assign (f2, 'd:\pols\data\car.dat');
assign(f3, 'mytext.txt');
Для работы с файлами из текущего каталога достаточно при вызове процедуры assign указать только полное имя файла (последний пример из выше приведённых).
Чтобы начать работу с файлом, требуется его открыть. Попытка работы с неоткрытым файлом приведет к ошибке. Существует две процедуры для открытия файла. Первая – Reset с одним параметром. Обращение к ней:
Reset( F);
Здесь F – файловая переменная. Эта процедура открывает существующий файл, связанный с файловой переменной F. Работая с файлами, приходится опираться на понятие - указателя в файле или файлового указателя. При открытии файла указатель устанавливается перед его первой компонентой.
Вторая процедура Rewrite также с одним параметром. Обращение к ней:
Rewrite(F);
Она создаёт и открывает новый файл, связанный с файловой переменной F. Если файл с указанным именем уже существует, то старый файл будет стёрт и создан новый пустой файл. Текущий указатель файла устанавливается в его начало.
В программе любой файл (файловая переменная) может быть открыт повторно, т. е. файл, первоначально открытый для чтения, может быть открыт для записи и наоборот. Одна и та же файловая переменная может быть связана с различными физическими файлами (но не одновременно).
Пример:
program p12_1;
var
f: file of byte;
begin
assign(f, 'c:\pols.txt');
rewrite (f) ;
........
close (f);
assign(f, 'c:\news.txt');
reset (f) ;
............
close (f) ;
end.
Часто важно знать находится ли указатель в конце файла (за последней компонентой)? В этом случае можно воспользоваться логической функцией Eof, которая возвращает значение true - если указатель в конце файла и false - если нет. Её параметром является файловая переменная.
Примеры фрагментов с использованием функции Eof:
t:= Eof(fl); { переменная t имеет значение true, если указатель находится в конце файла и равна false, если перед указателем находится хотя бы одна компонента файла. }
if Eof(f1) then... { если указатель находится в конце файла,
то выполнить … }
While not Eof (f2) do.... { если указатель находится не в конце
файла, то цикл продолжить … }
Указатель файла можно воспринимать как обычный номер текущей компоненты, которые нумеруются начиная с нуля. Таким образом, типизированные файлы являются структурой данных прямого доступа по номеру его компоненты.
Другой полезной функцией при работе с файлами является функция FileSize(f). Обращение к ней содержит только файловую переменную f. Результат выполнения функции FileSize - целое число размер файла или количество его компонент (тип Longint). Если функция возвращает ноль, то файл пуст.
Чтение из типизированного файла осуществляется процедурой Read.
Read (<файловая переменная>, <список переменных>);
Примеры:
Read(f , a);
Read, (f, a, b, с) ;
Переменные считываются из файла и после выполнения каждой операции считывания указатель файла перемещается на следующую компоненту.
program р12_2;
var
f: file of byte;
a, b, c: byte;
begin
assign(f, 'dospl. pas');
reset (f);
read (f, a, b, c);
writeln ('a= ', a, ' b= ', b, ' c= ', c);
close(f);
end.
Запись в файл осуществляется с помощью процедуры Write.
Write (<файловая переменная>, <список переменных>);
Переменные записываются в файл и, после каждой записи, указатель в файле перемещается за последнюю компоненту.
Для перемещения указателя по файлу можно использовать процедуру Seek. Обращение к ней:
Seek( f; n);
После вызова процедуры указатель файла f перемещается на компоненту с номером n. Например, вызов Seek(f, FileSize(f)); приведет к перемещению указателя в самый конец файла (за последнюю компоненту).
Для определения номера компоненты, на которой находится указатель файла, используют функцию FilePos. Обращение к ней: FilePos( f) .
Функция возвращает целое число - номер текущей компоненты (тип Longint). Если процедура FilePos возвратила значение 0, то указатель стоит в самом начале файла перед первой компонентой. Если функции FilePos и FileSize возвращают одинаковые значения, то указатель находится в самом конце файла.
После работы с файлом (файловой переменной) или перед повторным открытием для корректного взаимодействия с операционной системой его необходимо закрыть. С этой целью используют процедуру Close. Обращение к ней содержит только один параметр – файловую переменную.
Примеры:
program p12_3;
{ Создать файл, компоненты которого - квадраты натуральных
чисел от 1 до 100 }
var
f: file of Integer; { описываем файловую переменную }
i, t: integer;
begin
Assign(f, 'file.int'); { связываем файловую переменную с именем файла
на диске в текущем каталоге }
Rewrite(f); { создаём новый файл для записи }
for i :=1 to 100 do
begin
t:= sqr(i);
Write (f, t); { выводим в файл квадраты целых чисел }
end;
Close(f); { закрываем файл }
end.
program p12_4;
{ Открываем созданный предыдущей программой файл для чтения и
выводим его содержимое на экран }
var
f: file of Integer; { описываем файловую переменную }
i, t: integer;
begin
Assign (f, ' file.int' ) ; { связываем файловую переменную с
именем файла на диске}
Reset(f); { открываем файл для чтения }
While not Eof(f) do begin
Read(f, t); { читаем очередную компоненту из файла и }
Write(t:5, ' '); { выводим ее на экран }
end;
Close(f); { закрываем файл }
end.
Когда приходится хранить в файле информацию о множестве объектов, у каждого из которых много различных признаков (значений различного типа), компонентами типизированных файлов можно делать записи.
Задача. Создать программу, записывающую в файл данные о книгах, хранящихся в библиотеке. Для каждой книги требуется следующая информация: номер, фамилия и. о. автора, название книги, количество страниц и год издания.
program p12_5;
type
Books = record
n: Integer;
Avtor: String[45];
Nazv: String[70];
Str: Integer;
God: Integer;
end;
var
bf: file of Books;
r : Books;
n, i: integer;
begin
Write('Введите количество книг:');
Readln(n);
Assign(bf, 'bibl.dat'); { файл в текущем каталоге }
Rewrite(bf);
for i: = 1 to n do
begin
r. n:= i;
Write('введите фамилию и. о. автора:');
Readln(r.avtor);
Write('введите название книги:');
Readln(r.nazv);
Write('введите количество страниц:');
Readln(r.str) ;
Write('введите год издания:');
Readln(r.god) ;
Write(bf, r); { запись в файл очередной записи r }
end;
Close(bf);
end.
Задача. Из файла, компонентами которого являются записи - точки плоскости (record х, у: real; end;), выбрать только те, которые находятся в первой и третьей координатных четвертях и записать их в другой файл. Вывести на экран размеры первого и второго файлов.
program p12_6;
type
point = record
х, у: real;
end;
var
f1, f2: file of point;
p: point;
s1, s2: String;
i, nl, n2: Longint;
begin
Write('введите имя исходного файла:');
Readln(s1);
Write('введите имя результирующего файла:');
Readln(s2) ;
Assign(f1, s1); { связываем файловые переменные }
Assign(f2, s2); { с введенными именами файлов }
Reset (f1); { первый файл открываем для чтения, }
Rewrite(f2); { а второй для записи }
While not Eof (f1) do
begin
Read(f1, p); { Читаем очередную запись из первого файла. Если точка
принадлежит первой или третьей четверти, то выводим
ее во второй файл. }
if ((р.х > 0) and (p.у > 0)) or ((р.х < 0) and (p.у < 0))
then Write(f2, p);
end;
nl := FileSize(f1); { получаем объем первого файла }
n2:=FileSize(f2); { ... второго }
Writeln('nl= ', nl, ' n2 = ', n2);
Close(f1); { закрываем файлы }
Close (f2) ;
end.
Если мы открываем файл в программе, то неплохо бы предвидеть различные аварийные ситуации: отсутствует файл с таким именем, не вставлен диск в дисковод и др. При возникновении подобных ситуаций в обычном режиме программа прерывается по ошибке. Но существует возможность избежать этого: директива компилятору {$i-} выключает режим проверки и реакции на ошибки ввода/вывода, а директива {$i+} включает. Однако продолжить выполнение программы в аварийной ситуации недостаточно, важно запрограммировать реакцию на нее - обработать ошибку. Для этого предназначена функция без параметров IOResult (результат выполнения операции ввода/вывода). Функция возвращает целое значение. Если операция ввода/вывода не привела к ошибке, то ее значение ноль, в противном случае функция возвращает номер ошибки. Если ошибка произошла, то все последующие операции ввода/вывода игнорируются до тех пор, пока не будет вызвана функция IOResult.
Номера ошибок:
100 Disk read error (ошибка диска при чтению);
101 Disk write error (ошибка диска при записи);
102 File not assigned (файловая переменная не связана
с физическим файлом);
103 File not open (файл не открыт);
104 File not open for input (файл не открыт для ввода);
105 File not open for output (файл не открыт для вывода);
106 Invalid numeric format (недопустимый числовой формат).
Задача. Проверить существует ли файл с введенным с клавиатуры именем. Если существует, то получить файл с новым именем, в котором порядок следования компонент - байт, изменен на обратный.
program p12_7;
var
f1, f2: file of byte;
b: byte ;
sl, s2: String;
n, i: Longint;
begin
Write('введите имя исходного файла ');
Readln(s1);
Write('введите имя результирующего файла ');
Readln(s2);
Assign(f1, s1); { связываем файловые переменные с }
Assign(f2, s2); { введенными именами файлов }
{$i-} { - отключаем контроль ошибок в/в }
Reset (f1); { первый файл открываем для чтения }
if IOResult <> 0 then
begin
Writeln('Произошла ошибка, файл ', s1,' не существует.');
Halt; { прерываем программу }
end;
{$I+} { - включаем контроль ошибок в/в }
Rewrite(f2); { открываем второй файл для записи }
n := FileSize (f1); { n – длина 1-го файла }
for i := n - 1 downto 0 do
begin
Seek(f1, i); { - устанавливаем указатель на i-ую
компоненту первого файла }
Read(f1, b); { - читаем эту компоненту }
Write(f2, b); { и записываем во второй файл }
end;
Close(f1); { закрываем файлы }
Close (f2) ;
End.
Задача. Создайте программу, осуществляющую поиск по начальной части фамилии автора и выводящую на экран подходящие записи из файла о книгах (программа p12_5).
program p12_8;
type
Books = record
N : Integer;
Avtor : String[45];
Nazv : String[70];
Str : Integer;
God : Integer;
end;
var
bf : file of Books;
r : Books;
i : integer;
s : String;
begin
Write('Введите начальную часть фамилии автора:');
Readln(s);
Assign(bf, 'bibl.dat');
{Si-} { - отключаем контроль ошибок в/в }
Reset(bf); { файл открываем для чтения }
if IOResult <> 0 then
begin
Writeln('Произошла ошибка, файл bibl.dat не существует');
Halt; (прерываем программу}
end;
{$I+} { - включаем контроль ошибок в/в }
While not Eof(bf) do
begin
Read(bf, r);
{ Функция Pos(SubS, S) возвращает позицию, начиная с которой в
строке S располагается подстрока SubS (0 - S не содержит SubS). }
if pos(s, r. avtor) <> 0 then Writeln(r. n : 3, r. avtor : 12, r. nazv : 14,
r. str : 6, r. god : 8) ;
end;
Close(bf) ;
end.
Для работы с файловой системой нам могут понадобиться следующие процедуры из модуля System:
ChDir( s ) процедура изменяет текущий каталог. Здесь s – строка, содержащая путь к новому текущему каталогу.
Пример:
program p12_9;
Var
S: String;
begin
Write('Введите путь к каталогу:');
Readln(S);
{$i-}
ChDir(S);
if IOResult <> 0 then
Writeln('Данный каталог отсутствует');
end.
Следующая процедура GetDir(d; s) возвращает имя текущего каталога для заданного логического диска. Здесь d – выражение целого типа (byte); s – переменная типа string, передаётся по ссылке. (d = 0 - означает текущий логический диск, d =1 - диск A, d = 2 - диск В и т. д.)
Пример:
program p12_10;
var
s : String;
begin
GetDir (0, s) ;
Writeln (' текущий каталог:', s);
end.
Процедура procedure MkDir( s ) создает новый каталог. Здесь s - строковое выражение, содержащее путь и имя каталога. Следующая процедура RmDir(s) удаляет пустой каталог, где s – строка, содержащая путь и имя каталога.
Пример:
program p12_11;
var
S: String;
begin
S : = 'ABCD' ;
MkDir (S) ; { создаем новый каталог }
RmDir (S) ; { . . . и сразу его удаляем }
end.
Процедура Erase( f ) удаляет файл. Здесь f- переменная файлового типа, связанная с именем внешнего файла с помощью процедуры Assign.
Пример:
program p12_12;
var
F : file;
Ch : Char ;
S : String;
begin
Write (' Введите имя удаляемого файла:');
Readln(S);
Assign(F, S) ;
{$i-}
Reset (F) ;
if lOResult <> 0 then
Writeln (' файл ' , S, ' отсутствует')
else
begin
Close (F) ;
Write ( 'Удалять ', S, '? (y/no):' ) ;
Readln(Ch) ;
{ Function UpCase преобразует латинскую букву в заглавную.}
if UpCase(Ch) = 'Y' then Erase (F) ;
end;
end.
Процедура Rename( f, newname) переименовывает файл. Здесь f - переменная файлового типа, передаётся по ссылке; newname - строка, содержащая новое имя файла.
Пример:
program p12_13;
var
f : file;
S1, S2 : String;
begin
Write('Введите имя файла:');
Readln(S1);
Write('Введите новое имя файла:');
Readln(S2);
Assign(f, S1);
Rename(f, S2) ;
Writeln('Файл ', S1, ' переименован в ', S2);
end.