- •Введение в object pascal
- •Лекция 1. Интегрированная Среда и Состав языка Object Pascal
- •1.1 Работа с окнами
- •1.2 Редактирование в Object Pascal
- •1.3 Команды меню
- •1.4 «Горячие» клавиши в Object Pascal
- •1.5 Состав языка
- •1.5.1 Алфавит и ключевые слова
- •1.5.2 Идентификаторы
- •1.5.3 Знаки операций, разделители, выражения и операторы
- •Лекция 2. Описательная часть программы
- •2.1 Структура программы
- •2.2 Описание констант
- •2.3 Описание и использование меток
- •2.4 Комментарии
- •Лекция 3. Описание переменных
- •3.1 Структура раздела описания переменных
- •3.2 Классификация типов данных
- •3.2.1 Целочисленные типы
- •3.2.2 Логический тип
- •3.2.3 Символьный тип
- •3.2.4 Вещественные типы
- •3.3 Описание типов пользователя
- •Лекция4. Выражения
- •4.1 Порядок выполнения операций
- •4.2 Выражения целого типа
- •4.3 Вещественные выражения
- •4.4 Логические выражения
- •Лекция 5. Программы Линейной структуры
- •5.1 Операторы ввода (Read, Readln)
- •5.2 Операторы вывода (Write, Writeln)
- •5.2.1 Форматирование численных значений
- •5.2.2 Вывод строковых, символьных и логических значений
- •5.2.3 Вывод вещественных значений в экспоненциальном формате
- •5.2.4 Расположение данного в поле вывода. Примеры
- •5.3 Оператор присваивания
- •5.4 Составной оператор
- •5.5 Стандартные процедуры и функции
- •5.5.1 Понятие процедуры и функции
- •5.5.2 Описание некоторых стандартных процедур и функций
- •5.5.3 Примеры программ линейной структуры
- •Лекция 6. Операторы ветвления (выбора)
- •6.1 Оператор ветвления if
- •6.2 Оператор множественного выбора (варианта) - case
- •Лекция 7. Операторы организации циклов
- •7.1 Цикл типа for
- •7.1.1 Прямая форма оператора for
- •7.1.2 Обратная форма оператора for
- •7.1.3 Советы для начинающих и примеры
- •7.2 Цикл типа While
- •7.3 Цикл типа Repeat... Until
- •7.4 Дополнительные операторы при программировании циклов
- •7.4.1 Досрочный выход из цикла - break
- •7.4.2 Переход к следующей итерации цикла - continue
- •Лекция 8. Массивы
- •8.1 Одномерные массивы
- •8.2 Сортировка одномерного массива
- •8.3 Массивы с большей размерностью
- •8.4 Констант-массивы
- •8.5 Генератор случайных чисел
- •8.5.1 Описание функции Random
- •8.5.2 Применение случайных чисел при работе с массивами
- •Лекция 9. Строки
- •9.1 Строковый тип
- •9.2 Операции над строками
- •Лекция 10. Записи и множества
- •10.1 Запись
- •10.2 Множества
- •11 Пользовательские процедуры и функции
- •11.1 Описание функции и процедуры
- •11.2 Понятие формальных и фактических параметров
- •11.3 Способы передачи параметров в подпрограмму через заголовок
- •11.4 Область видимости идентификаторов
- •12 Файлы
- •12.1 Основные понятия
- •12.2 Типизированные файлы
- •12.3 Текстовые файлы
12 Файлы
12.1 Основные понятия
Файлы в программе – это каналы, по которым можно выполнять передачу данных. Под файлом понимают именованный набор данных, которые считываются или записываются на внешние устройства.
В языке Object Pascal имеются три вида файлов: текстовые, типизированные и нетипизированные.
Файловая система Паскаля — это часть DOS (дисковой операционной системы). Она имеет древовидную структуру (смотри рис. 12.1).
Корневой каталог, например диска С (логические диски имеют идентификаторы соответствующие буквам английского алфавита - А, В, С, D... ) может содержать подкаталоги, в которых возможно находятся другие подкаталоги и т. д. В корневом каталоге и во всех подкаталогах содержатся файлы. На рисунке 12.1 в корневом каталоге находятся два каталога TURBO и TOOLS. Оба, в свою очередь, содержат по 4 файла.
С:
TURBO
BIN
BGI
EXAMPLE
UNIT
TOOLS
ARC
SYS
MOUSE
DRIVERS
Рис.12.1. Пример файловой системы на диске С
Любой файл характеризуется основным именем и расширением, которые разделяются точкой. Основное имя состоит максимум из восьми символов, а расширение - максимум из трех символов. Расширение, как правило, указывает на предназначение файла. Например, pas - текст программы на Object Pascal, txt - текстовый файл, dat - файл с данными и т. п.
Примеры:
turbo.ехе
met_pas.pas
tools.с
gol_txt
autoexec.bat
Каким образом программы, работающие с файлами, знают, где находятся необходимые файлы, в каком именно подкаталоге? Для решения этой проблемы при передаче программе или подпрограмме "местонахождения" файла можно воспользоваться понятием - путь к файлу. В Object Pascal путь к файлу - это символьная строка, заключенная в апострофы. Она формируется из имени логического диска и имен системы вложенных подкаталогов, последним из которых является тот, где непосредственно находится файл. В строке имена подкаталогов разделяются символом "\" (обратный слэш).
Примеры:
'C:\TURBO\BGI'
'D:V'
'D:\ARM\BLM\STOP'
'C:\TOOLS\MOUSE'
В операционной системе есть понятие - текущего подкаталога или буквально — подкаталога, на котором находится указатель операционной системы. Все файловые операции, при которых явно не указывается путь к файлу, происходят именно в текущем подкаталоге.
Файлом (файловой переменной) в Object Pascal является объект типа file. При использовании файловой переменной необходимо учитывать следующие ограничения:
1.Файловой переменной не разрешается присваивать другое значение.
2. Если требуется передать файловую переменную в процедуру или функцию, то соответствующий параметр передают по ссылке, т.е. используют ключевое слово Var.
Работа с файлом, в общем случае, включает четыре операции:
установление соответствия между файловой переменной и файлом на внешнем устройстве;
открытие файла;
чтение информации или запись её в файл;
закрытие файла.
12.2 Типизированные файлы
Типизированный файл состоит из последовательности однотипных или одинаковых компонент и может содержать различное их число (возможно ни одной).
Тип компонент файла практически любой, но он не должен содержать внутри себя других файлов. Определяются файловые переменные следующим образом:
<список идентификаторов файловых переменных>:
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.