Типизированные файлы

Типизированный файл состоит из последовательности однотипных или одинаковых компонент и может содержать различное их число (возможно ни одной).

Тип компонент файла практически любой, но он не должен содержать внутри себя других файлов. Определяются файловые переменные следующим образом:

 

<список идентификаторов файловых переменных>:

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.