Турбо Паскаль вводит ряд стандартных процедур, применимых к файлам любых типов (табл. 12.2). Кроме этого, существует ряд их расширений и специальных процедур для работы с различными типами файлов. Такие процедуры будут рассматриваться в разделах, посвященных различным типам файлов. Описания процедур ввода и вывода данных Write, WriteLn, Read и ReadLn не включены в этот раздел, так как они достаточно сильно различаются при работе с разными типами файлов, а иногда (при работе с бестиповыми файлами) и вовсе теряют смысл.
В Турбо Паскале не определены процедуры ввода и вывода в файлы Get(f) и Put(f), и их функции выполняют другие процедуры ввода-вывода. Не определено также обращение к буферной переменной f^.
Таблица 12.2
Процедура или функция | Действие |
Assign(VAR f; FileName: String) | Связывает файловую переменную f с именем физического файла, заданным в строке FileName |
Reset(VAR f) | Открывает файл с логическим именем f для чтения |
Rewrite(VAR f) | Открывает файл с логическим именем f для записи |
Close(VAR f) | Закрывает канал ввода-вывода файла с логическим именем f |
Rename(VAR f; NewName: String)) | Переименовывает физический файл, ранее связанный с файловой переменной f, в имя NewName. Должна вызываться до открытия файла (применима лишь к закрытым файлам) |
Erase(VAR f) | Стирает (если это возможно) физический файл, связанный с файловой переменной f с носителя информации. Стираемый файл должен быть закрытым {225} |
EOF(VAR f): Boolean | Возвращает значение True, если достигнут конец файла f, т.е. из него ничего уже нельзя прочитать или файл пуст. Иначе возвращает False |
Файловая переменная f может иметь любой файловый тип.
Связывание файлов
Процедура Assign (VAR f; FileName: String) устанавливает связь между логическим файлом, описываемым файловой переменной f любого файлового типа, и конкретным файлом MS-DOS, название которого содержится в строковом параметре FileName. Иными словами, логический файл f связывается с физическим файлом FileName. Строка FileName может содержать имя файла на диске (в том числе полное имя файла), имя стандартного устройства MS-DOS ('CON', PRN' и т.п.) или пустую строку '':
|
Assign(f, 'file.dat'); {связь с файлом текущего каталога }
Assign(f, 'a:\x.pas'); {связь с файлом x.pas на диске А: }
Assign(' f, 'LPT2'); {связь со вторым принтером ПЭВМ }
Assign(f, ' '); {связь со стандартным файлом, как правило файлом 'CON' }
Имя физического файла должно быть корректным и уникальным. Нельзя вставлять символы шаблонов '*' и '?' в имя файла, но можно связывать файловые переменные с еще не существующими файлами на диске (для дальнейшего их создания).
Процедура Assign не занимается анализом корректности имени файла и безоговорочно связывает заданное имя с логическим файлом f. Логический файл при этом считается закрытым, а размер буфера файла — неопределенным. Если файл f связан с некорректным именем, то это вызовет ошибку ввода-вывода лишь при попытке произвести любое действие над ним (будь то открытие файла, удаление его или что-либо другое).
Будучи однажды установленной, связь между файловой переменной f и физическим файлом сохраняется до следующего вызова Assign с той же переменной f. Это означает, что можно проделывать различные операции с файлом f, лишь единожды связав его с физическим файлом: {226}
Assign(f, 'TEST.TMP'); { установлена связь }
Rewrite(f); { открытие файла для перезаписи }
Write(f,...); { запись в файл f }
Close(f); { закрытие файла (вызов необязателен) }
|
Reset(f); { открытие файла для чтения }
Read(f,...); { чтение из файла f }
Close(f); { закрытие файла (вызов обязателен) }
Erase(f); { удаление файла с диска }
После того как логический файл связан с физическим, его можно открыть для чтения или записи.
Открытие файлов
Процедуры открытия файлов Reset(VAR f) и Rewrite(VAR f) открывают логический файл f для чтения данных (Reset) или записи (Rewrite). Если процедуры выполняются успешно (открытие файла происходит без ошибки), то файл становится открытым и готов к чтению или записи первого элемента в нем. Эти же процедуры фиксируют размер буфера файла (он устанавливается автоматически, если только не был переопределен вызовом SetTextBuf для файлов типа Text или расширенной записью Reset/Rewrite для бестиповых файлов).
После открытия файла (и только после него!) становится возможным чтение или запись данных. Процедуры открытия могут применяться многократно к одному и тому же файлу. Если файл был до этого открыт, то он автоматически предварительно закрывается. Повторный вызов Reset переустановит последовательность чтения вновь на самый первый элемент файла, при этом потеря данных исключена. Но повторное обращение к Rewrite сотрет текущее содержимое файла и подготовит файл к заполнению с первого элемента. Между повторными вызовами процедур открытия не обязательно вставлять оператор закрытия файла Close. Советуем также внимательно просмотреть разд. 12.11 «Обработка ошибок ввода-вывода».
Закрытие файлов
Процедура Close (VAR f) закрывает открытый до этого логический файл f. Попытка закрыть уже закрытый (или еще неоткрытый) файл вызовет сбой программы. Процедура не изменяет связь между файловой переменной f и физическим файлом, но назначает им текущее состояние «закрыт». Это особенно важно для файлов, открытых для записи. Закрытие файла гарантирует сохранность и полноту заполнения. Так, фатальная ошибка в программе {227} уже не сможет повлиять на содержимое файла после его закрытия.
|
Заметим, что если программа прервалась из-за ошибки и до закрытия файла, то он все же будет создан на носителе, но содержимое последнего буфера не будет перенесено в файл. То же самое может случиться и в том случае, если вообще забыть поставить в программу вызовы Close.
Вызовы процедуры Close необходимы при завершении работы с файлами. Также необходимо закрывать открытые файлы перед их удалением (Erase) или переименованием (Rename).
Переименование файлов
Процедура Rename(VAR f; NewName: String) позволяет переименовать физический файл на диске, связанный с логическим файлом f. Процедура выполнима только с закрытым файлом, в противном случае возникнет сбой.
Предполагается, что файловая переменная f была предварительно связана вызовом процедуры Assign с неким физическим файлом, например FileName. Вызов Rename (f, NewName) сменит имя физического файла с FileName на NewName. В принципе, процедура Rename выполняет ту же работу, что и команда REN в MS-DOS. Правда, в отличие от последней Rename не может содержать в строковом параметре символы '*' и '?'.
Рассмотрим фрагмент программы (рис. 12.1).
VAR f: File of Real; BEGIN Assign(f, 'A:\REAL.DAT'); { установлена связь } Rewrite(f); { открытие файла для записи } Write(f,...); { запись в файл f } Close(f); { обязательно закрытие файла} {Пусть теперь надо сменить имя файла 'REAL' на 'FLOAT'} Rename(f, 'A:\FLOAT.DAT'); { Готово! } |
Рис. 12.1
Переименование происходит при закрытом файле f. После него можно снова открывать файл, но f будет связана уже с новым именем. Старый файл не резервируется (его имя 'A:\REAL.DAT' замещено на 'A:\FLOAT.DAT').
Будет ошибкой так переименовывать имя, что изменится имя диска и путь к файлу. Например, заведомо ошибочен второй оператор: {228}
Assign(f, 'A:\FILE.AAA');
Rename(f, 'C:\FILE.BBB');
поскольку, кроме имени файла, изменяется содержащий его диск. Ведь таким образом мы задаем перенос файла с А: на С:, а лишь затем его переименование. Перенос же, как и копирование, не определен в языке, и его надо конструировать средствами Турбо Паскаля или использовать внешний вызов командного процессора MS-DOS (см. процедуру Exec модуля DOS).
Удаление файлов
Процедура Erase (VAR f) уничтожает (стирает) физический файл на носителе (диске). Файловая переменная f должна быть предварительно связана с существующим физическим файлом. Сам файл к моменту вызова Erase должен быть закрыт.
Чтобы уничтожить файл с именем FileName, достаточно конструкции:
Assign(f, FileName); Erase(f);
где f — файловая переменная любого типа.
Если файл с именем FileName не существует, возникнет сбой при попытке уничтожить его.
Анализ состояния файлов
Логическая функция EOF(VAR f): Boolean возвращает значение True, когда при чтении достигнут конец файла f. Это означает, что уже прочитан последний элемент в файле или файл f после открытия оказался пуст. Во всех остальных случаях функция возвращает значение False. Состояние EOF обновляется автоматически при каждом обращении к процедуре ввода данных. Файл f должен быть открыт.
Обращение к EOF без указания файла соответствует анализу конца стандартного файла Input (как правило, связанного с клавиатурой). Стандартный файл считается текстовым, и конец файла в нем обозначен символом #26 (в прочих, нетекстовых файлах, явного обозначения конца файла не существует).
Назначение функции EOF — указывать на возникновение конца файла. Наиболее часто EOF используется в цикле while, читающем файл до конца:
while not EOF(f) do { пока не достигнут конец файла f,}
Read(f,...); { читать данные из этого файла} {229}
Эта конструкция гарантирует, что чтение прекратится только после считывания последнего элемента в файле с логическим именем f. Обратите внимание, что используется именно цикл while...do, а не repeat...until. Функция EOF постоянно следит за статусом чтения и позволяет опознать конец файла до того, как мы его непосредственно прочитаем.
Текстовые файлы
Определение «текстовые файлы — это те, которые выдают или принимают текстовую информацию» в целом правильно, но не слишком развернуто. Дадим другое определение: текстовые файлы — это файлы, в которых:
1) информация представляется в текстовом виде посредством символов в коде ASCII;
2) порции информации могут разделяться на строки. Признаком конца строки служит символ #13 (код 13 — CR). Он может быть объединен с символом перевода строки #10 (код 10 — LF);
3) конец файла обозначается явно символом ^Z (код 26);
4) при записи чисел, строк и логических значений они преобразуются в символьный (текстовый) вид;
5) при чтении чисел и строк они автоматически преобразуются из текстового представления в машинное.
Бытовые примеры текстовых файлов просты. Если файл можно вывести на экран в текстовом режиме и прочитать его, то это — текст. Клавиатура посылает в компьютер «сплошной» текст-файл. Компьютер посылает на принтер текст-файл, даже если принтер рисует в графическом режиме. Рассмотрим коротенький текст-файл:
Текст-файл [13][10] Вы читаете текстовый файл, который [13][10] может храниться на диске или печататься [13][10] на принтере.[13][10] В нем можно хранить цифровые записи чисел:[13][10] 123 456 789 0[13][10] 234 567 890 1[13][10] 1.2 3.4 5.60 4[13][10] -100.254 [13][10] Конец файла[13][10] [26] |
{230}
Цифры в квадратных скобках — управляющие коды с тем же номером, т.е. [13]=#13. в файле они занимают по одному символу и в текстовых режимах, как правило, на экран и принтер не выводятся (но управляют выводом).
Заметьте, что каждая строка заканчивается признаком конца строки, даже пустая (1-ая сверху). Самый последний символ в файле — признак его конца. Реально файл хранится как сплошная последовательность символов и разбивается на строки лишь при его выводе на экран или печать. Пустой текстовый файл содержит один символ #26.
Для работы с текстовым файлом необходимо определить файловую переменную (переменную логического файла):
VAR
f: Text;
и дальше связать ее с физическим файлом стандартной процедурой Assign, после чего файл можно открывать.
В системной библиотеке Турбо Паскаля определены две текст-файловые переменные: Input и Output. Они связаны с устройством 'CON' (или фиктивным устройством CRT, если подключен модуль CRT) автоматически. И если в процедурах ввода опущено имя файла, то считается, что ввод идет из системного файла Input (это клавиатура), а если имя файла опущено в операторе вывода, то в файл Output (вывод идет на экран).
Текстовые файлы в Турбо Паскале — это вовсе не аналоги файлов типа File of Char. Знак равенства между этими типами можно поставить лишь со значительными оговорками.