Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Паскаль (ст 33).doc
Скачиваний:
4
Добавлен:
13.11.2019
Размер:
822 Кб
Скачать
☆

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

1. Назначение.

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

2. Описание файловых переменных для типизированных файлов.

Файловая переменная, обозначающая типизированный файл, описывается следующим образом:

Var

<имя_файловой_переменной> : File of <тип_компонентов>;

где <тип_компонентов> - любой стандартный тип, определенный в Pascal (кроме файлового) либо тип, определенный пользователем в разделе Type (кроме файлового).

Пример.

Type Stroka=Srtring[15];

Var

F1 : File of Integer; {файл с целочисленными компонентами}

F2 : File of Stroka; {файл со строковыми компонентами}

3. Процедуры и функции работы с типизированными файлами.

а) К типизированным файлам применимы процедуры Assign, Reset, Rewrite, Close, Rename, Erase и функция Eof.

б) Функция FileSize.

Назначение:

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

Синтаксис:

FileSize( F ), где F – файловая переменная.

Описание работы:

  • функция FileSize возвращает целое число в диапазоне от 0 до 231-1, которое равно количеству компонентов в файле;

  • если файл пуст, то функция возвратит 0.

Примечание:

  • аргументом функции не может быть файловая переменная текстового файла;

  • файл должен быть открыт до применения функции.

в) Функция FilePos.

Назначение:

определение текущей позиции указателя обработки.

Синтаксис:

FilePos( F ), где F – файловая переменная.

Описание работы:

  • функция FilePos возвращает целое число в диапазоне от 0 до 231-1, которое равно текущей позиции (или номеру компонента, на который установлен указатель);

  • если текущая позиция соответствует началу файла, то функция возвратит 0;

  • если текущая позиция соответствует концу файла, то FilePos( F ) =

= FileSize( F ).

Примечание:

  • аргументом функции не может переменная текстового файла;

  • файл должен быть открыт до вызова функции.

г) Процедура Seek.

Назначение:

непосредственный доступ к заданному компоненту файла прямого доступа.

Синтаксис:

Seek( F, N ), где F – файловая переменная, N – номер нужного компонента, представляет собой целое число в диапазоне от 0 до 231-1.

Описание работы:

  • процедура Seek перемещает текущий указатель к компоненту с номером N (первый компонент в файле имеет номер 0);

  • для расширения файла предусмотрена возможность перемещения на конец файла, это осуществляется с помощью функции FileSize:

Seek(F, FileSize(F)).

Примечание:

  • процедуру Seek нельзя использовать для текстовых файлов;

  • файл должен быть открыт до вызова этой процедуры.

д) Процедура Truncate.

Назначение:

усечение файла

Синтаксис:

Truncate( F ), где F – файловая переменная.

Описание работы:

процедура Truncate отсекает часть файла от текущего положения указателя до конца, при этом текущая позиция файла становится концом файла.

Примечание:

  • процедура Truncate не может применяться к текстовым файлам;

  • файл должен быть открыт до вызова процедуры.

Задача 1. Создать файл Lab.dat из 20 целых чисел.

Program Dat;

Uses Crt;

Var

F : File of Iinteger;

i, j: Integer;

Begin

Assign(F, ‘Lab.dat’);

{$I-}

Rewrite(F);

{$I+}

If Ioresult <>0

Then Begin

Writeln (‘Нет места на диске’);

Halt;

End;

Randomize;

For i:=1 to 20

Do Begin

j:=Random(100);

Write(F, j);

End;

Close(F);

End.

{файловая переменная}

{рабочие переменные}

{установление связи F с внешним файлом}

{отключение контроля ошибок ввода/вывода}

{открытие файла для записи}

{включение контроля ошибок ввода/вывода}

{если Ioresult 0}

{то вывод «На диске нет места»}

{ и окончание работы программы}

{формирование типизированного файла}

{закрытие файла}

Связь между файловой переменной и внешним файлом устанавливается процедурой Assign. Открытие файла для записи осуществляется процедурой Rewrite. Если на диске нет места, то на экране появляется соответствующее сообщение и файл не создается. При наличии места на диске с помощью оператора For создается файл из 20 целых чисел. При этом каждый раз используется генератор случайных чисел, который инициализируется процедурой Randomize. Запись в файл производится через переменную j, т. к. с помощью процедуры Write (Writeln) в типизированный файл можно записать только значение переменной, выражения в этом случае использовать нельзя.

Задача

Заменить нулем все компоненты с нечетными номерами файла Lab.dat, созданного с помощью программы Dat.

Program Prim;

Uses Crt;

Var

F: File of Iinteger;

Name: String;

Size, i, II, j: Integer;

Procedure Wywod;

Begin

While not Eof(F)

Do Begin

Read(F, J);

Write(J, ‘ ’);

End;

Writeln;

End;

Begin

Repeat

Write(‘Входной файл >’);

Readln(Name);

Assign(F, Name);

{$I-}

Reset(F);

{$I+}

II:= Ioresult;

If II<>0

Then Writeln(‘Файл’,Name,’ не найден’);

Until II=0;

Wywod;

Writeln(‘Для продолжения нажать Enter’);

Readln;

Size:=FileSize(F);

For i:=1 to (Size div 2)

Do Begin

Seek(F, 2*i - 1);

j:=0;

Write(F, j);

End;

Writeln(‘Результирующий файл’);

Seek(F, 0);

Wywod;

Close(F);

Readln;

End.

{файловая переменная}

{имя файла}

{рабочие переменные}

{процедура вывода файла на экран}

{в цикле}

{ввод имени файла Lab.dat}

{установление связь F с внешним файлом}

{отключение контроля ошибок ввода/вывода}

{открытие файла для чтения для записи}

{включение контроля ошибок ввода/вывода}

{присваивание II значения Ioresult}

{если II 0}

{то вывод сообщения «Файл…не найден»}

{постусловие: пока не открыт нужный файл}

{вывод исходного файла}

{Size = число компонентов в файле}

{в цикле по i}

{перемещение указателя к следующему}

{нечетному компоненту}

{замена нулем нечетного компонента}

{конец цикла For}

{перемещение указателя в начало файла}

{вывод полученного файла}

{закрытие файла}

Объяснить (!!!). Открытие файла для чтения осуществляется стандартной процедурой Reset. С помощью процедуры Reset можно также открыть файл для его корректировки. Значение стандартной функции Ioresult присваивается рабочей переменной II, так как после повторного обращения к функции Ioresult (после вывода сообщения «Файл не найден») ее значение меняется, т. к. вывод на экран всегда корректен. Если открывается несуществующий файл на диске, то на экране появится сообщение «Файл … не найден» и снова будет запрашиваться имя входного файла. В данном примере надо ввести имя файла Lab.dat. С помощью стандартной функции Filesize определяется число компонентов в файле. Для перемещения указателя обработки к заданному компоненту используется процедура Seek. При определения длины файла оператором

Size:=Filesize(F);

и организации доступа к компонентам файла с помощью операторов вызова процедуры Seek

Seek(F, 2*I-1) (Seek(F, 0))

используются переменная Size типа Integer и выражение 2*i - 1 типа Integer. Для вывода на экран результирующего файла текущую позицию в файле надо переместить в начало. Для этого применяется процедура

Seek(F, 0);

Внутренняя процедура Wywod используется для вывода исходного и результирующего файлов.

Входной файл Lab.dat

61 41 37 91 81 15 60 10 51 5 98 18 32 84 42 46 77 75 99 62

Результирующий файл

61 0 37 0 81 0 60 0 51 0 98 0 32 0 42 0 77 0 99 0

Результаты выполнения программы Prim.

Тип – запись

1. Реальные данные об объектах часто описываются величинами разных типов. Например, товар на складе описывается следующими величинами: наименование (String), количество (Integer), цена (Real), наличие сертификата качества (Boolean) и т. д. В этом случае возникает необходимость хранить и обрабатывать совокупности данных различного типа, поэтому приходится использовать отдельные массивы для каждого типа данных, а для установления соответствия между ними вводятся соответствующие индексы. Такой подход не очень удобен и существенно усложняет написание программы. В Pascal существует другой способ решения таких задач – использование комбинированного типа данных, который называется запись. Запись – это структурированный тип данных, состоящий из фиксированного числа компонентов одного или нескольких типов.

2. Определение типа записи начинается идентификатором Record и заканчивается зарезервированным словом End. Между ними заключен список компонентов, называемых полями, с указанием идентификаторов (имен) полей и типа каждого поля (см. ниже). Тип запись можно описывать:

а) в разделе описания типов

Type

<имя_типа_записи> = Record

<имя_поля_1> : <тип_поля_1>;

< имя_поля_2> : < тип_поля_2>;

…

< имя_поля_k> : < тип_поля_k>;

End;

Var

<имя_переменной> : <имя_типа_записи>;

б) явно в разделе описания переменных

Var

<имя_переменной> : Record

<имя_поля_1> : <тип_поля_1>;

< имя_поля_2> : < тип_поля_2>;

…

< имя_поля_k> : < тип_поля_k>;

End;

Пример 1.

Type

Car = Record {объявление записи из 4-х полей}

Number : Integer; {номер}

Marka : String[20]; {марка}

FIO : String[40]; {фамилия и инициалы владельца}

Address : String[60]; {адрес владельца}

End; {окончание описания записи}

Var

M, V : Car; {объявление переменных типа- запись}

Идентификатор (<имя_поля_...>) поля должен быть уникален только в пределах записи, т. е. в разных записях поля могут иметь одинаковые имена. Однако во избежание ошибок лучше делать его уникальным в пределах всей программы.

<тип_поля_...> - любой стандартный тип языка Pascal, включая тип запись, т. е. поле записи может быть в свою очередь записью. Если в качестве <тип_поля_...> используется тип, определенный пользователем, то он должен быть объявлен до описания записи.

Из записей одного типа можно составлять массивы

Пример 2.

Type

Person = Record

FIO : String[20];

Age : Integer;

Prof : String[30];

End;

Var

List : Array[1..50] of Person;

3. Обращение к значению поля осуществляется с помощью составного имени, которое состоит из имени переменной типа запись и идентификатора поля, разделенных точкой. Например, чтобы получить доступ к полям записи Car (см. пример 1), надо написать:

M.Number, M.marka, M.FIO, M.Address.

Составное имя можно использовать везде, где допустимо применение типа поля (применение данных такого же тира, как и поле записи). Для присваивания полям значений используется оператор присваивания.

Пример.

а) присваивание полям записи значений в программе (см. пример 1):

M.Number :=1678;

M.Marka :=’ГАЗ-24’;

M.FIO :=’Иванов И. И.’;

M.Address :=’Ул. Пушкина 12-31’;

б) присваивание полям одной записи значений полей другой записи (см. пример):

V:=M;

Обращение к полям записи имеет несколько громоздкий вид, что неудобно при использовании длинных идентификаторов. Для решения этой проблемы в Pascal предназначен оператор присоединения With … Do:

With <переменная_типа_запись>

Do <оператор>;

где <переменная_типа_запись> - имя переменной типа запись, с полями которой нужно работать, <оператор> - простой или составной оператор языка Pascal. Один раз указав имя переменной типа запись в операторе With, можно в пределах этого оператора работать с именами полей как с обычными переменными, т. е. без указания перед идентификатором поля имени переменной, определяющей запись.

Пример.

With M

Do Begin

Number :=1678;

Marka :=’ГАЗ-24’;

FIO :=’Иванов И. И.’;

Address :=’Ул. Пушкина 12-31’;

End;

Примечание. Оператор присоединения действует только на поля записи, указанной в операторе присоединения. Все поля, относящиеся к другой записи, используются только с указанием идентификатора записи.

4. Операции с записями:

  • ввод записи с клавиатуры:

Read(M.Number, M.Marka, M.FIO, M.Address);

  • вывод записи на экран монитора:

Writeln(M.Number:4, M.Marka:7, M.FIO:12, M.Address:25);

  • чтение записи из текстового файла:

Read(<имя_файла>, M.Number, M.Marka, M.FIO, M.Address);

  • вывод значения переменной в текстовый файл:

Writeln(<имя_файла>, M.Number:4, M.Marka:7, M.FIO:12, M.Address:25);

  • сравнение записей:

If M.Fam <> V.Fam

Then …

Если операции с записью производятся в пределах оператора присоединения, то указываются только имена полей записи, указанной в операторе присоединения. Во всех остальных случаях обязательно полное указание имени поля записи (составное имя).

Задача

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

Program Primer;

Uses Crt;

Type

Anketa = Record

Fam, Nm, Ot : String[15];

Born : Integer;

End;

Var

F : File of Anketa;

A : Anketa;

S : Char;

Begin

Assign(F,’Swed.dat’);

Rewrite(F);

Clrscr;

Repeat

With A

Do Begin

Write(‘Фамилия: ’);

Readln(Fam);

Write(‘Имя: ’);

Readln(Nm);

Write(‘Отчество: ’);

Readln(Ot);

Write(‘Год рождения: ’);

Readln(Born);

End;

Write(F, A);

Writeln(‘Продолжить (y/n)’);

Readln(S);

Until Upcase(S)=’N’;

Close(F);

End.

{объявление типа - запись}

{файловая перем. типизированного файла}

{А - запись}

{символьная переменная}

{установление связи между F и Swed.dat}

{открытие файла на запись}

{в цикле}

{для записи А}

{ввод значений полей записи А}

{с клавиатуры}

{запись записи А в файл}

{вывод запроса на продолжение}

{ввод ответа с клавиатуры}

{пока не нажата ‘N’ или ‘ n’}

{закрытие файла}