For d in week do writeln(d)
End.
Действие цикла эквивалентно обычному арифметическому циклу For...to вида:
for d:=Low(week) to High(week) do writeln(d);
Вторая возможность применения цикла For...inзаключается в использовании в качестве перечисляемого типа массива (array).
Пример 9. Код программы, аналогичной примеру 8, с использованием массива:
var a: array[1..7] of string
=(’monday’,’tuesday’,’wednesday’,’thursday’,’friday’,
’saturday’,’sunday’); s : String;
begin
For s in a do writeln(s)
End.
Третья возможность применения цикла For...inзаключается в использовании в качестве перечисляемого типа множества (set). В этом случае тело цикла выполняется для всех элементов множества.
Пример 10. Код программы, аналогичной примеру 8, с использованием множества:
var week:set of TWeekDay= [monday,tuesday,wednesday,thursday,friday];
d: TWeekday;
begin
For d in week do writeln(d)
End.
Пример 11. Код программы, в которой:
1) на основе базового множества M байтового типа, содержащего все целые числа от 0 до 20, при помощи присваивания инициализируются простые множества байтового типа: M0={множество всех целых чисел от 5 до 15}, M2={ множество всех четных целых чисел от 0 до 20}, M3={ множество всех целых чисел от 0 до 20, кратных 3},
2) определяются три составных множества а)Ms1:=(M2+M3)-M0, б) Ms2:=M2*M3, в) Ms3:=M0-M3, которые выводятся на экран при помощи цикла For...in.
Текст программы дан с необходимыми комментариями:
type M = Set of 0..20;{описание базового множества М}
var element:byte;{описание вспомогательной величины байтового типа element}
M0,M2,M3,Ms1,Ms2,Ms3:M; {описание простых множеств M0,M2,M3и составных Ms1,Ms2,Ms3}
Begin
M0:=[5,6,7,8,9,10,11,12,13,14,15]; {инициализация простых множеств M0,M2,M3}
M2:=[0,2,4,6,8,10,12,14,16,18,20];
M3:=[0,3,6,9,12,15,18];
Ms1:=(M2+M3)-M0; {формирование составного множества Ms1}
Ms2:=M2*M3; {формирование составного множества Ms2}
Ms3:=M0-M3; {формирование составного множества Ms3}
writeln; write(’ SET Ms1: ’); {вывод составного множества Ms1}
for element in Ms1 do write(element,’ ’);
writeln; write(’ SET Ms2: ’); {вывод составного множества Ms2}
for element in Ms2 do write(element,’ ’);
writeln;write(’ SET Ms3: ’); {вывод составного множества Ms3}
for element in Ms3 do write(element,’ ’);
End.
Вопросы для проверки знаний.
1. В чем заключается математический смысл понятий множества, элемента и подмножества, составляющих основу множественного типа данных ?
2. Назовите основные отличия множеств от массивов.
3. Какие два способа описания применяют для переменных множественного типа и каков их синтаксис ?
4. Что называют битовым представлением множеств ?
5. Какие операции над множествами называют предметными, какой результат они дают и какие предметные операции применяют в Паскале ?
6. Что называют операциями сравнения, какой результат они дают и какие операции сравнения есть в Паскале ?
7. Определить результат применения операции объединения к парам множеств:
а) ['a','c','e'] и ['b','e']; б) ['с','e','g'] и ['b','c','d','e']; в) ['a','b','c'] и [0,1]; г) [1,3,5] и [2,3,4,5,6] ?
8. Определить результат применения операции пересечения к парам множеств:
а) ['a','c','e'] и ['b','e']; б) ['с','e','g'] и ['b','c','d','e']; в) ['a','b','c'] и [0,1]; г) [1,3,5] и [2,3,4,5,6] ?
9. Определить результат применения операции вычитания к парам множеств:
а) ['a','c','e'] и ['b','e']; б) ['с','e','g'] и ['b','c','d','e']; в) ['a','b','c'] и [0,1]; г) [1,3,5] и [2,3,4,5,6] ?
10. Для каких типов величин возможно применение цикла типа For...in?
11. Каков синтаксис цикла For...in ?
12. Можно ли применить цикл For...in к типу char?
Практическое задание.
1. Разработать программу, в которой:
1) вводится базовое множество М[0..10] и величина А типа М, содержащая все нечтные значения из М,
2) по запросу с клавиатуры вводятся две произвольные величины В и С типа М,
3) определяются составные множества, равные а) объединению А,В,С, б) пересечению и определяются числа элементов в них, которые выводятся на экран.
Записи
Записями называют связанные структуры, состоящие из нескольких элементов, называемых полями, которые могут иметь одинаковые или различающиеся типы и, соответственно размеры в памяти. Поля могут иметь любой тип, допустимый в Паскале (базовый или объявленный пользователем), кроме файлового. Полям задают собственные имена.
Структура записи похожа на одномерный массив, в котором элементы-поля могут иметь разные типы. Поэтому доступ к ним осуществляется не через индекс (номер элемента в массиве), а с использованием имени поля. Например, унифицированные краткие сведения о книгах имеют следующую структуру: автор, название книги, издательство, год издания, её цена. Первые три элемента относится к строковому типу данных, четвертый к целому, а цена - к вещественному типу. Над элементами записи можно выполнять действия, допустимые для данных этого типа.
Как и для других типов в Паскале, описание записи может быть дано в двух формах:
1) при помощи специального типа record или
2) непосредственным описанием соответствующей переменной.
Синтаксис описания типа record имеет вид:
Type
имя типа = record описание всех полей записи end;
где record, end - служебные слова,
имя типа - любой разрешенный идентификатор Паскаля,
описание всех полей записи– список описаний полей, разделяемых “;” (после последнего описания перед end разделитель можно не ставить).
Синтаксис непосредственного описания переменной с именем имя переменной(любой разрешенный идентификатор Паскаля), имеющейтип record:
Var
имя переменной: record описание всех полей записи end;
Для записей, как и для массивов, допускаются вложенные описания, в которых описание отдельного поля тоже может быть записью.
Пример 1. Разработать описание типа Pers_Data для записи, содержащей следующую информацию о сотрудниках фирмы: 1) фамилия, 2) домашний адрес, 3) телефон, 4) электронную почту, 5) должностной оклад. Ввести переменную данного типа с названием P_Data.
Решение. Дадим полям 1)-5) соответственно названия fam;adr;tel;e_mail;salary. Первые 4 поля являются строковыми величинами. Исходя из содержания вводимой в них информации, им присвоим длины 20,40,15,20. Последнему полю 5) присвоим вещественный тип:
type Pers_Data=record
fam:string[20]; adr:string[40]; tel:string[15];
e_mail:string[20]; salary:real
End;
var P_Data: Pers_Data;
Пример 2. Дать непосредственное описание переменной с именем P_Data, в которой содержится тот же тип информации, что и в примере 1.
Решение:
var P_Data: record fam:string[20]; adr:string[40]; tel:string[15];
e_mail:string[20]; salary:real
End;
Как целый объект запись может использоваться только в операторах присваивания, у которых в левой и правой частях стоят имена записей одинакового типа. Все остальные действия рассчитаны на работу с отдельными полями записей. Для обращения к ним при присвоении значений или их обработке применяют составные имена, которые состоят из имени записи, разделяющей точки и имени поля.
Пример 3. Примеры присваивания значений именам полей fam, tel иsalary у переменной-записи с именем P_Data из примера 2 имеют вид:
P_Data. fam:='Андреев Б.В.';
P_Data. tel:='85662223322';
P_Data. salary:=36500.00;
Составные имена позволяют обращаться к полям записей из любой части кода программного блока, где они описаны.
Для перехода к обычным именам (без имени записи и разделяющей точки ) можно применить оператор присоединения with. Его синтаксис имеет вид:
with имя записи do оператор;
где оператор– оператор (простой или составной), задает область действия оператора присоединения, в пределах которой можно не использовать составные имена.
Пример 4. Применение оператора присоединения для выполнения действий из примера 3:
With P_Data do begin
fam:= 'Андреев Б.В.';
tel:='85662223322';
salary:=36500.00
End;
Для начальной засылки значений в поля записей (инициализации) в коде программы наряду с обычными присваиваниями можно использовать типизированные константы.
Пример 5. Инициализация значений полей записи, которая имеет тип Pers_Data, данный в примере 1, с использованием типизированной константы Andreev того же типа:
Const
Andreev: Pers_Data=(fam:'Андреев Б.В.';
adr:'105141,Moscow,Krasnaya Presnya street,37-125';
tel:='85662223322';
e_mail:'[email protected]'
salary:=36500.00);
При создании и хранении наборов однотипных записей необходимо использовать массивы из переменных типа record. Для этого можно использовать описание новых типов, представляющих собой массивы из записей, либо непосредственно описывать переменные-массивы из элементов-записей.
Пример 6. Для хранения данных по сотрудникам фирмы “Альфа”, необходимо описать массив записейwoker_ALPHA типа Pers_Data, данного в примере 1. Возможно использование двух вариантов:
1) вариант с промежуточным описанием нового типа (массива записей) woker_firm:
type woker_firm: array [1..30] of Pers_Data;
var woker_ALPHA: woker_firm;
2) вариант с непосредственным описанием переменной-массива woker_ALPHA:
var woker_ALPHA: array [1..30] of Pers_Data;
Записи, имеющие постоянную структуру (состав полей), называют фиксированными (англ.-fixed records). Наряду с ними в Паскале есть возможность использовать записи с вариантами (англ.-records with variant parts), в описании которых используется зарезервированное слово case, позволяющее задавать несколько вариантов заполнения специальному полю записи. Такой вид записей удобно использовать для хранения в записях одного типа таких данных, у которых основная часть полей имеет совпадающий тип, но имеются поля, в которые может заноситься различающаяся по типу информация. В любом типе записи может присутствовать только одна вариантная часть, которая должна располагаться после описания всех полей с фиксированными типами. Она может быть как именованной, так и неименованной.
Синтаксис строки, открывающей вариантную часть записи:
case [имя селектора :] тип селектора of:
После данной строки идут строки, которые начинаются очередным значением селектора, за которым стоит двоеточие и описание поля для данного варианта значения селектора. Если имя селектора не задано, его называют безымяынным.
Все варианты значений соответствующего поля занимают в памяти одно и то же адресное пространство памяти. Поэтому для конкретного объекта нужно указывать только одну из альтернатив, задаваемых селектором.
У записей с вариантами внесение данных в фиксированные поля производится так же, как и у фиксированных записей. Заполнение вариантной части записи начинается с уcтановки значения варианта заполнения поля, которое выполняется в виде присваивания необходимой величины селектору. Затем производится обычное присваивание значений.
Если селектор безымянный, то при заполнении вариантной части записи присваивания полям выполняют через их составные имена, как и для фиксированных полей.
Пример 7. Рассмотрим пример программы, содержащей тип записи с вариантами, имеющей безымянный селектор, описание записи данного типа, засылку данных в ее поля и вывод их содержимого на экран:
Type
TVarRec = record{ начало описания типа}
ch: char;
case byte of{ Используется безымянный селектор }
1: (i: integer);{ поле i имеет целый тип integer }
2: (d: double);{ поле d имеет вещественный тип double }
end; { коней описания типа}
var Rec: TVarRec; { описание переменной Rec типаTVarRec }
begin{ начало тела основной программы}
Rec.ch:='A'; { присваивание значения символьному полю ch }
Rec.i := 5;{ присваивание значения целому полю i }
writeln(' Field values 1: Rec.ch=',Rec.ch,' Rec.i=',Rec.i);{вывод значений полей}
Rec.d:= Rec.d + 1.2345;{ изменение значения вещественного поля d}
writeln(' Field values 2: Rec.ch=',Rec.ch,' Rec.i=',Rec.i,' Rec.d =',Rec.d);
End.
В итоге работы программа выдаст на экран следующие данные:
Так как оба поля вариантной части i и d начинаются по одному и тому же адресу, то изменение значения вещественного поля dизменило ранее вставленное значение целого поля i .
Пример 8. Необходимо выполнить следующие действия:
а) разработать тип записиTCircle, в которой будет содержаться информация об окружности на декартовой плоскости,
б) описать переменные Circle_1, Circle_2этого типа.,
в) ввести в поля переменной Circle_1данные, используя их составные имена, взять второй вариант данных в вариативном поле, вывести содержимое полей на экран,
г) ввести в поля переменной Circle_2данные, используя оператор присоединения with, при третьем варианте данных в вариативном поле, вывести содержимое полей на экран.
Решение. Так как цвет и толщина линии, которой изображается окружность, должны быть заданы всегда, для любой окружности, то соответствующие им поля в типе TCircle должны иметь постоянный тип.
Вариативную часть типа TCircle задает набор геометрических условий, задающих положение и размер плоской окружности. Простейшими возможными вариантами являются:
1) декартовы координаты центра (xc,yc) и радиус окружности r,
2) координаты центра (xc,yc) и диаметр окружности d,
3) три точки с декартовыми координатами (x1,y1),(x2,y2),(x3,y3), не лежащие на одной прямой, через которые проходит окружность.
С учетом предложенного состава описания типа TCircle получим следующий код, решающий поставленную задачу:
type TCircle = record
color: byte; {описание цвета}
width: real; {описание толщины линии}
case g: byte of{варианты задания размера и положения окружности на плоскости}
1:(xc,yc,r: real);{декартовы координаты центра (xc,yc) и радиус окружности r }
2:(xc1,yc1,d: real);{декартовы координаты центра (xc,yc) и диаметр окружности d }
3:(x1,y1,x2,y2,x3,y3:real);{дек.координаты трех точек, через которые проходит окружность}end;
var Circle_1,Circle_2: TCircle; {описания окружностей Circle_1,Circle_2}
begin{начало тела основной программы}
Circle_1.color:=15;{засылка данных в Circle_1 с использованием составных имен полей}
Circle_1.width:=0.5; Circle_1.g:=2;
Circle_1.xc1:=20.5; Circle_1.yc1:=33.8; Circle_1.d:=10.0;
writeln(' Circle_1: color=',Circle_1.color, {вывод данных по Circle_1}
' width',Circle_1.width:8,' variant geom=',Circle_1.g);
writeln(' xc1=',Circle_1.xc1:8,' yc1',Circle_1.yc1:8,' d=',Circle_1.d:8);
with Circle_2 do{засылка данных в Circle_2 с использованием оператора присоединения with}
Begin
color:=12; width:=1.5; g:=3;
x1:=20.5; y1:=33.8; x2:=20.5; y2:=33.8; x3:=20.5; y3:=33.8;
writeln(' Circle_2: color=',color,' width',width:8,' variant geom=',g);
writeln(' x1=',x1:8,' y1',y1:8,' x2=',x2:8,' y2',y2:8,' x3=',x3:8, 'y3',y3:8);
End;
End.
Вариантный характер записи можно использовать не только при занесении в нее информации, но и при ее чтении – одна и та же конкретная запись может быть прочитана при различном истолковании типа ее вариантных полей.
Вопросы для проверки знаний.
1. Что называют записями и полями записей ?
2. Какова структура записи ?
2. Укажите две формы задания типа записи ?
3. Какие имена называют составными и как их используют для доступа к содержимому полей записи?
4. Как можно организовать доступ к полям записи без использования составных имен?
5. Какие записи называют записями с вариантами и когда целесообразно их использовать?
6. Какую структуру имеют записи с вариантами ?
7. Можно ли одновременно применить несколько вариантов типов поля в вариантной части записи ?
Практическое задание.
1. Выполнить следующие действия:
а) разработать тип записиTRectangle, в которой будет содержаться информация о прямоугольнике на декартовой плоскости со сторонами, параллельными осям, который полностью задан цветом линии, координатами левой верхней и правой нижней вершин,
б) описать переменные Rect_1, Rect_2этого типа,
в) ввести в поля переменной Rect_1данные, используя их составные имена, вывести содержимое полей на экран,
г) ввести в поля переменной Rect_2данные, используя оператор присоединения with, вывести содержимое полей на экран.
Файлы
Разработка файлового типа данных (файлов) обусловлена необходимость организации обмена данными, содержащимися в оперативной памяти компьютера, с периферийными устройствами ПК для их ввода-вывода, долговременного хранения (диск, флэш-память) или последующей обработки (принтер, сканер). Практическая реализация обмена данными с использованием файлов основана на понятиях физического и логического файлов.
Физический файлпредставляет собой именованную область памяти на некотором внешнем носителе. Также физический файл может означать некоторое внешнее устройство или порт ПК, через который организуется доступ к данным устройствам. Физический файл имеет имя, представляющее собой строковую величину, в которой наряду с названием файла может быть указан путь к нему, тип файла (путем задания расширения) и т.д. Например, в Паскале физические файлы могут иметь имена вида:
'F1.dat'{расширение в имени означает тип файла}
'c:\Мои документы\book1.doc'{в имени дан полный путь файла по правилам ОС MS DOS}
'file2'{имя файла не содержит ни пути к нему, ни расширения}
Физические файлы также называют дисковыми, поскольку операционная система, управляющая всей памятью компьютера, делит ее на отдельные части – диски.
Под логическим файлом понимают упорядоченную совокупность произвольного числа однотипных компонент. Величины данных компонент генерируются в программе либо получают при считывании из физического файла. Тип компонент может быть любым, допустимым в Паскале, кроме файлового. Т.е. нельзя создавать файл, состоящий из файлов. В программе логическому файлу соответствует переменная файлового типа, которая представляет собой обычный идентификатор Паскаля. Для того, чтобы устанавливать соответствие логических файлов с физическими, в алгоритмических языках применяют специальные функции.
Передачу информации из логических файлов, генерируемых программами и содержащимися в оперативной памяти ЭВМ, в физические файлы называют их записью. Обратный процесс передачи информации из физического файла в логический называют чтением. Оба процесса осуществляются конкретными устройствами под управлением операционной системы.
Определение логического файла схоже с определением массива, однако в отличие от них, у файлового типа данных при его описании не указывается длина (количество элементов), т.е. она не определена и ограничивается только свободным объемом используемой памяти.
9.5.1. Описание файловых переменных
В Паскале переменная файлового типа может быть описана одним из 3 способов:
1. Типизированный файл – в описании указывается тип компонент файла (любой, разрешенный в Паскале, кроме файлового). Синтаксис описания имеет вид:
имя файловой переменной = file of тип компонент файла;
2. Текстовый файл – специальный тип файлов, для работы с которыми используются особые процедуры либо общие процедуры имеют особенности. Синтаксис описания текстового файла имеет вид:
имя файловой переменной = text;
Текстовый файл представляет собой последовательность строк разной длины, состоящих из символов. Каждая строка текстового файла завершается маркером конца строки EoLN, в конце всего файла (как и любого другого) стоит текстовый маркер конца файла EoF. К элементам текстового файла возможен только последовательный доступ, начиная с первого. Параллельное выполнение записи и чтения в текстовый файл не допускается.
3. Нетипизированные файлы – тип компонент не задан. Синтаксис описания имеет вид:
имя файловой переменной = file;
Вид файла задает способ хранения и методы обработки информации, хранящейся в нем. Поэтому необходимо контролировать правильность объявления как вновь создаваемых , так и уже имеющихся файлов.
Пример 1. Описания типов и файловых переменных:
Type
string_12= String [12]{описание типа строковой величины из 12 символов}
string_25= String [25]{описание типа строковой величины из 25 символов}
string_150= String [150]{описание типа строковой величины из 150 символов}
P_data = record{описание типа - записи}
name: string_150;
adr : string_150;
tel : string_12;
End;
Data_Str = file of string_25;{описание файлового типа с компонентами string_25}
Var
f_char: file of char; {описание фaйла с компонентами -символами}
f_int: file of integer; {описание фaйла с компонентами – целыми числами}
file_dif: file;{описание нетипизированного фaйла}
f_chapter: text; {описание текстового фaйла}
f_P_Dat: file of P_data;{описание фaйла с компонентами –записями типа P_data}
fD: Data_Str;{присваивание переменной fD файлового типа Data_Str}
f_str12: file of string_12; {описание фaйла с компонентами типа string_12}
9.5.2. Стандартные операции с файлами. Связывание логических и физических файлов
Реальный способ записи, чтения и хранения физического файла определяется типом используемого для этой цели внешнего носителя. Общим для всех устройств внешней памяти является то, что их физическая структура на элементарном уровне разбита на битовые элементы памяти, предназначенные для хранения одного из двух значений 0 или 1. Поэтому перед записью логические файлы всегда кодируют в двоичной системе счисления при помощи 0 и 1. В таком виде они хранятся на внешнем носителе и считываются с него.
Поскольку в Паскале для файлов, в отличие от других типов, не работают обычные операции (даже присваивание), то все действия с ними выполняют при помощи специальных подпрограмм. По назначению действия с файлами можно разделить на четыре группы:
1) организация доступа к файлам,
2) подготовка к вводу – выводу данных из файла и его закрытие,
3) ввод – вывод данных из файла,
4) вспомогательные операции с файлами.
Рассмотрим выполнение данных действия с файлами и соответствующие подпрограммы, вначале – организацию доступа к физическим файлам. Связывание файловой переменной с именем f_log(идентификатор Паскаля), задающей в программе логический файл, с физическим файлом, имеющим имя F_f (строковая величина), выполняется вызовом процедуры аssign:
Аssign(f_log, F_f);
Здесь и далее имя физического файла F_f можно задавать как в виде строковой константы, так и в виде строковой переменной. После связывания физический файл становится доступным программе. Связь действует до завершения работы программы или до ее отмены.
В процедуре аssign предусмотрена дополнительная возможность вместо имени физического файла использовать зарезервированное имя, закрепленное за некоторым устройством ПК. Это позволяет использовать это устройство для ввода-вывода информации вместо физического файла. В MS DOS за основными внешними устройствами ПК зарезервированы следующие имена:
1) CON(консоль), под ней при вводе данных система принимает клавиатуру, при выводе - монитор ПК,
2) PRN, LPT1, LPT2, LPT3 – имена, зарезервированные за принтерами (ПК может иметь доступ к нескольким печатающим устройствам), имена PRN и LPT1 являются синонимами, т.е. взаимозаменяемы,
3) AUX(от англ.Auxilary - вторичный)- аналоговый порт для ввода-вывода непрерывных сигналов (показания датчиков, звук и др.),
4)COM1, COM2 (от англ. COMmunication port), COM-порт- двунаправленный последовательный (передача информации по одному биту) интерфейс для обмена байтовой информацией с внешними устройствами,
5) NUL - фиктивное внешнее устройство.
Если физический файл связан с логическим файлом (через его файловую переменную), то он становится доступным программе для выполнения с ним ввода- вывода данных, а также других действий.
Также в Паскале по умолчанию всегда существуют два стандартных имени физических файлов INPUT и OUTPUT, которые ассоциируются соответственно с клавиатурой и экраном компьютера.
9.5.3. Ввод и вывод данных из физических файлов. Вспомогательные действия
Практическая реализация обмена данных с физическими файлами включает две стадии – подготовку к обмену и сам обмен.
Подготовка физических файлов к вводу – выводу. Вспомогательные действия по подготовке к обмену данными с физическим файлов выполняют при помощи процедур reset, rewrite,append, сlose и логической функции EOF .
Вначале необходимо открыть физический файл с заданием направления передачи данных (чтение из файла или запись данных в файл). Для открытия применяют процедуры reset, rewrite,append, причем процедуры reset иrewrite применяют для открытия файла любого вида, а процедуру append - только для открытия текстового файла.
reset. Открытие физического файла, с которым связана файловая переменная f_log, для чтения осуществляется вызовом процедуры reset:
Reset(f_log);
Если данная процедура успешно выполнена, т.е. физический файл найден, то он готов к считыванию из него компонент, начиная с самой первой. Если же указанный физический файл не найден, то выполнение процедуры завершается выдачей сообщения об ошибке. Типизированные и нетипизированные файлы процедура reset одновременно открывает для чтения и записи.
rewrite.Открытие физического файла, связанного с файловой переменной f_log, для записи в него данных с начала файла производится вызовом процедуры:
Rewrite(f_log);
Если rewrite выполнена успешно, то физический файл готов к записи в него первого элемента. Если этот файл уже содержал в себе данные, то при новой записи все они уничтожаются. Применение процедурыrewrite к текстовому файлу открывает его только для записи, а к типизированному или нетипизированному файлу - одновременно и для записи, и для чтения. Если процедуру rewrite применить к несуществующему файлу, то она создаст новый файл (в отличие от reset , которая в этом случае выдает сообщение об ошибке).
append . Открытие физического файла, связанного с файловой переменной f_log, для записи в него информации в конце файла (добавление данных):
Append(f_log)
сlose. Закрытие ранее открытого физического файла, связанного с файловой переменной f_log, производится вызовом процедуры сlose:
Сlose (f_log);
Вызов сlose необходим для завершения работы с файлом. Если он не произведен, то соответствующий переменной f_log физический файл остается открытым.
EOF(End Of File). После вызоваEOF(f_log), который обычно производится в условии оператора if, данная функция возвращает значение TRUE, в двух случаях:
1) при чтении достигнут конец физического файла, связанного с файловой переменной f_log, т.е. прочитан его последний элемент,
2) открытый физический файл оказался пустым.
Получение значения False, означает, что чтение физического файла не закончено.
Ввод – вывод данных. После открытия физического файла в системе вводится указатель на его элементы. В каждый момент времени для обработки (чтения или записи) доступен только один элемент файла - тот на который установлен указатель. При открытии с помощью процедур reset, rewrite он устанавливается на начальный элемент файла (имеющий номер 0), затем перемещается по элементам в процессе чтения или записи. При открытии с помощьюappend указатель устанавливается на конечный элемент файла. Для осуществления ввода информации в файл и вывода из него в Паскале используют процедурыread, readln, write, writeln, которые имеет свои особенности, зависящие от типа файла (текстовый или типизированный). Для перемещения по элементам файла используют процедуру Seek, для усечения - процедуру Truncate. Контроль ошибок ввода/вывода можно выполнять с помощью функции IOResult.
read (readln). Синтаксис процедуры read имеет вид:
read (f_log,v1[,v2,…,vn]);
где f_log - текстовая или типизированная файловая переменная,
v1,v2,…,vn - переменные, имеющие тот же тип, что и элементы f.
Выполнение данной процедуры приведет к тому, что в переменныеv1,v2,…,vnбудут записаны n элементов физического файл, начиная с места, на который показывает указатель, после чего он переместится на n позиций в сторону возрастания их номера.
При чтении:
1) в переменную типа char помещаются отдельные символы из файла,
2) в переменную типа string помещается количество символов, равное длине строки, если до этого не встретились символы конца строки или конца файла,
3) при считывании в числовую переменную пропускаются символы-разделители, начальные пробелы и считывается значение числа до появления следующего разделителя.
Процедураreadln аналогична read, с той разницей, что при чтении текстового файла после считывания данных, указанных в списке ввода, пропускаются все оставшиеся символы в данной строке, включая метку конца строки.
write(writeln). Синтаксис процедуры аналогичный:
write (f_log,v1[,v2,…,vn]);
Выполнение ее приведет к тому, что в физический файл, начиная с места, на который показывает указатель, будут записаны n элементов со значениями v1,v2,…,vn. После чего указатель переместится на n позиций, как и при чтении. Если на местах записи были какие-либо значения, они заменяются новыми. Если указатель находится в конце файла (после его последнего элемента), то при записи очередного элемента он дополняет файл. При этом длина файла увеличивается на 1.
Процедураwriteln аналогична write, с той разницей, что при формировании текстового файла после записи всех значений, взятых из переменных, дополнительно записывается метка конца строки. После этого следующая запись начнется с новой строки.
Поскольку по умолчанию в Паскале всегда открыты два стандартных имени физических файлов Input (клавиатура) и Output(экран монитора), то к ним можно обращаться без предварительного связывания их с какой-либо файловой переменной (и, соответственно, не закрывать их). Вызовы вида
Read(Input, x,y);
write(Output, 'Вывод на экран величины а=',а,);
означают:
1) чтение с вводимых с клавиатуры (с эхо-повтором на экране) двух величин и передачу их значений в переменные с именами x,y (при несоответствии типов вводимых величин и x,y будет выдано сообщение об ошибке),
2) последовательный вывод на экран в одной строке текстовой величины 'Вывод на экран величины а=' и значения величины а.
Поскольку имена Input и Outputявляются стандартными, их можно не упоминать при вводе и выводе. Два последних вызова эквивалентны обычным операторам ввода и вывода:
Read(x,y);
write('Вывод на экран величины а=',а,);
Seek. Перемещение указателя на элементы файла, связанного с файловой переменной f_logна позицию с номером k выполняется вызовом процедуры:
Seek(f_log, k);
Данная процедура реализует прямой метод доступа к элементу с любым номером в типизированных файлах. Номер позиции может задавать константа, переменная или выражение целого типа. Он должен находиться в допустимых пределах - от 0 до n-1, если файл содержит n записей.
Truncate. Усечение файла, связанного с файловой переменной f_log,начиная с текущей позиции, выполняется вызовом процедуры:
Truncate(f_log);
После данной процедуры из файла удаляются все элементы, начиная с текущего и до последнего.
IOResult. Обращение к функции возвращает целое число, соответствующее коду последней ошибки ввода - вывода. При отсутствии ошибок функция вернет 0. Для применения функции IOResultв программенеобходимо отключать автоконтроль данных ошибок, используя директиву компилятора {$i-}. Например, если неизвестно наличие физического файла, соответствующего файловой переменной ft, то для проверки можно использовать следующий код:
{$i-} reset(ft); {$i+}
if IOresult<>0 then writeln ('File ',FileName,' not existent')
else writeln ('File ',FileName,' open for reading');
Вспомогательные действия с физическими файлами. Для переименования и уничтожения физических файлов применяются процедуры rename и erase. Перед их применением файл должен быть закрыт. Целочисленная Функция fileSize возвращает размер файла.
rename. Вызов
Rename(f_log, F_f);
приводит к переименованию физического файла, связанного с файловой переменной f_log, после которого он получит новое имя F_f.
erase. Вызов
Erase(f_log);
уничтожает физический файл, связанный с файловой переменной f_log.
FileSize. Вызов
FileSize(f_log) ;
возвращает текущее значение числа элементов в типизированном файле. Оно на единицу больше, чем номер последнего элемента, поскольку нумерация элементов начинается с 0. Применение fileSize зачастую упрощает выполнение многих действий. Например, установку указателя на первое свободное место в файле f_log можно выполнить вызовом Seek(f_log, FileSize(f_log)).
Перечисленные процедуры и функции позволяют создавать физические файлы, связывать их с логическими, производить обмен данными между ними.
9.5.4. Примеры решения задач по обработке текстовых файлов
Поскольку наиболее распространенными на практике являются текстовые файлы, рассмотрим решение задач характерных для этого типа файлов.
Пример 2. Необходимо:
1) создать в каталоге FPC корневого каталога диска С текстовый файл с именем rmas.txt, 2) ввести с клавиатуры число элементов строкового массива n,
3) записать в открытый файл в виде отдельных строк значения вида (2*i+1), где(1≤i ≤n),
4) открыть файл для чтения с проверкой правильности,
5) считать все строки файла, вывести их на экран в отдельных строках.
Код программы дан с необходимыми комментариями:
var i:byte;n:integer; ft:text; FileName,st:string;
Begin
FileName:='c:\fpc\rmas.txt';{задание полного имени физического файла}
write(' Vvedite razmernost n:');readln(n); {запрос и ввод числа элементов массива n}
assign(ft,FileName); {связывание логического и физического файлов}
rewrite(ft);{открытие физического файла для записи}
for i:=1 to n do
begin str(2*i+1,st);writeln(ft,st) end; {запись элементов в физический файл}
{$i-} {отключение режима автоконтроля ошибок ввода- вывода}
reset (ft); {открытие физического файла для считывания}
{$i+}{включение режима автоконтроля ошибок ввода- вывода}
if IOresult<>0{проверка наличия ошибок при открытии файла}
then writeln ('File ',FileName,' not existent')
else writeln ('File ',FileName,' open for reading');
i:=0; writeln('File ',FileName,' content :');
while not(eof(ft)) do{ циклическое считывание элементов файла до получения eof }
Begin
i:=i+1; readln(ft,st);
writeln('file element number ',i,' is equal to ',st);
End;
close(ft); {закрытие физического файла}
End.
Пример 3. Зачастую для ускорения обработки данных их переписывают из физического файла в массив, содержащийся в оперативной памяти. Рассмотрим процедуру rewriting, решающую данную задачу для текстовых файлов произвольной длины, а также внешнюю программу, содержащую необходимые описания, вызов процедуры и вспомогательные действия. В процессе переписывания строк из физического файла ft в массив Art происходит параллельный подсчет числа строк n (числа элементов в массиве). Поскольку размерность выходного массиваArt неизвестна, он описан в заголовке процедуры rewriting как открытый. Для его приема во внешней программе введен статический массив Mas_st размерности 100. Для отладки и проверки работы программы в качестве текстового файла выбран test.txtв каталогеFPCна дискеC. Во внешней программе в него заносятся 8 значений (i2+1) при 1£i£8 в виде строк.
var i,Lmas:integer; ft:text; FileName:string;
Mas_st:array [1..100] of string;
procedure rewriting (var ftext:text; var Art:array of string; var n:integer);
begin{тело процедуры rewriting }
n:=0;
reset(ftext); {открытие физического файла для чтения}
While not Eof(ftext) do
Begin
inc(n);readLn(ftext,Art[n-1]);{наращивание счетчика, чтение строки из файла в массив}
End;
close(ftext); {закрытие файла}
End;
begin{тело основной программы}
FileName:='c:\fpc\test.txt';{задание имени физическому файлу}
assign(ft, FileName);{связывание логического и физического файлов}
rewrite(ft); {открытие файла для записи}
for i:=1 to 8 do writeln(ft,i*i+1);
rewriting(ft,Mas_st,Lmas);{вызов процедуры для записи содержимого из файла в массив}
writeln(' Lmas = ',Lmas);
for i:=1 to Lmas do writeln(' Mas[',i,']= ',Mas_st[i]);
End.
В результате работы программа должна вывести Lmas =12 и значения, переписанные из файла в массив {2 5 10 17 26 37 50 65}.
Пример 4. Поиск слова (заданной последовательности символов) в текстовом файле произвольной длины. Решение задачи оформлено в виде отдельной процедуры search_word,в которую имя файла передается в виде входного параметра, а слово вводится с клавиатуры по запросу. Если слово содержится в строке файла, процедура выдает ее номер, если слово не входит ни в одну строку, то процедура выводит сообщение “No”.
Для отладки и проверки работы программы в качестве текстового файла выбран тот же файл c:\fpc\test.txt, в который заносится то же содержимое, что и в примере 3.
Для поиска вхождения слова в строку используется функция рos,которая при вхождении выдает номер первой позиции, иначе возвращает 0. Код программы дан с необходимыми комментариями:
var n,i:integer; ft:text; FileName:string;
procedure search_word (var ftext:text; var n:integer);
var str,w_s:string;
begin{тело процедуры search_word }
writeln(' Vvedite slovo:'); read(w_s);
n:=-1;
reset(ftext); {открытие физического файла для чтения}
While not Eof(ftext) do
Begin
inc(n);readLn(ftext,str);{наращивание счетчика, чтение строки из файла в строку str }
if pos(w_s,str)<>0 then{проверка вхождения слова в строку}
begin writeln('word ',w_s,' is fined in line’,n);close(ftext); exit end;
End;
writeln('NO');
close(ftext); {закрытие файла}
End;
begin{тело основной программы}
FileName:='c:\fpc\test.txt';{задание имени физическому файлу}
assign(ft, FileName);{связывание логического и физического файлов}
rewrite(ft); {открытие файла для записи}
for i:=1 to 8 do writeln(ft,i*i+1);
search_word(ft,n);{вызов процедуры поиска слова, вводимого с клавиатуры, в заданном файле}
End.
Вопросы для проверки знаний.
1. Какую общую задачу решает файловый тип данных ?
2. Что понимают под физическим файлом и как задается его имя ?
3. Что понимают под логическим файлом и как задается его имя ?
4. Какие процессы называют записью и чтением файлов ?
5. Назовите три файловых типа в Паскале, каков синтаксис их описания ?
6. Что представляют собой типизированные файлы ?
7. Что представляют собой текстовые файлы ?
8. Назовите основные группы действия с файлами.
9. Как осуществляется связывание логического и физического файлов.
10. Какие имена зарезервированы за внешними устройствами ПК в MS DOS ?
11. Что означают стандартные имена физических файлов INPUT и OUTPUT ?
12. Какие процедуры и функции применяют для подготовки физических файлов к вводу – выводу ?
13. Какие процедуры и функции используют для ввода и вывода данных из файлов ?
14. Какие действия относят к вспомогательным при работе с файлами и какие процедуры и функции применяют для их выполнения ?
Практические задания.
1. Отладить программу из примера 4 п.9.5. Модифицировать процедуру в ней таким образом, чтобы она выполняла поиск строки, задаваемый с клавиатуры, в заданном текстовом файле.
2. Разработать функцию NumWord, которая подсчитывает количество слов в заданном текстовом файле при условии, что слова в строке могут разделяться пробелами, запятыми и точками, а слова в разных строках разделяются признаком конца строки. Также разработать текст основной программы для отладки и тестовых испытаний функции NumWord.
.