type
A = record
I,J: Integer;
S: String[20];
end;
var
F: File of A;
То получим очень интересную картину, когда файл содержит в качестве элементов записи. Мы сможем их читать, писать и производить с ними действия. Именно этим мы и займемся в процессе модификации нашей программы "Записная книжка".
File - нетипизированный файл. Когда мы указываем в качестве типа файла просто File, то есть без типа:
F: File;
То получаем "нетипизированный" файл, чтение и запись в который отличается от работы с файлами других типов. Эти действия производятся путем указания количества байт, которые нужно прочитать, а также указанием области памяти, в которую нужно прочитать эти данные. Это тема будущих выпусков.
Итак, разобрались с типами файлов. Теперь давайте по порядку разбирать действия, применяемые для работы с файлами. Я говорил о них выше.
Связывание переменной с файлом
Самый универсальный шаг. Выполняется одной и той же процедурой для всех типов файлов, а именно процедурой Assign:
Assign(_переменная_файлового_типа_, 'путь к файлу');
Как видите, в качестве параметров задаются переменная либого файлового типа и строка - путь к файлу, который, по правилам DOS, не может быть длиннее 79 символов. Вот пример использования assign:
var |
T: Text; |
F1: File of Byte; |
F2: File; |
begin |
Assign(T, '1.txt'); |
Assign(F1, 'C:ProgrammTp2.txt'); |
Assign(F2, 'F:usr_inapacheconfhttpd~1.con'); |
.......... |
Как видите, это очень просто и сама процедура Assign проблем не вызывает. Давайте теперь рассмотрим следующий этап.
Открытие файла
Открытие файла - это уже более усложненный процесс, нежели связывание с ним переменной. Здесь учитывается, зачем открывается файл - для записи или чтения, а также в зависимости от типа файла процедуры выполняют различные действия.
Тем не менее этот процесс не сложен и заключается в использовании одной из трех имеющихся процедур:
Reset(_любая_файловая_переменная_);
Открыват файл на чтение. В качестве параметра - файловая переменная любого из перечисленных выше типов. Это может быть текстовый, типизированный либо не типизированный файл. В случае с текстовым файлом, он открывается только на чтение. В случае с типизированным и нетипизированным файлом - он открывается на чтение и запись.
Append(T: Text);
Эта процедура открывает текстовый файл (только текстовый!) на запись. Выше я сказал, что Reset при задании параметра типа Text не позволит писать в него данные, открыв файл лишь для чтения. То есть если вы используете текстовый файл и хотите производить в него запись, нужнo использовать Append. Если чтение - Reset. В остальных случаях дело обходиться одной процедурой Reset.
Также обратите внимание, что если вы до этого уже открыли файл на чтение, вам не нужно закрывать его и открывать снова на запись. В этом случае файл закрывается сам и открывается заново. При записи данных в файл при открытии его с помощью этой процедуры они записываются в конец файла.
ReWrite(F) - создает новый файл либо перезаписывает существующий. Будьте осторожны, если не хотите случайно удалить нужный файл. Напомню, файл, открытый с помощью этой процедуры будет полностью перезаписан.
В использовании процедур, думаю, проблем не будет. Однако возникает другой вопрос - что, если файла, который открывается, нет? Если он не существует на диске, то как мы сможем из него читать информацию? Программа выбьет ошибку в такой ситуации. Это реальная проблема, которая, кстати, очень просто решается.
Способ проверки заключается в двух этапах: использовании ключей компилятора и функции IOResult, которая возвращает значение от только что выполненной операции ввода-вывода. С функцией разберемся быстро, а вот с такой штукой как ключи компилятора мы еще не сталкивались, поэтому остановимся подробнее.
Ключи компилятора - это обыкновенные переключатели, которые контролируют ход выполнения программы исключая или включая реакцию на какие-нибудь условия. В нашем случае нас интересует условие, когда физически отсутствует нужный нам файл, либо не удалось открыть его по другим причинам. Ключей у Паскаля довольно много, мы пока изучим один, необходимый нам на данный момент.
Оформляются ключи следующим образом: в скобках комментариев "{}" первым символом после открывающей скобки "{" ставиться знак доллара "$", после чего указывается имя ключа и его значение. Нас интересует ключ, который выключает вывод ошибок ввода-вывода, называется он "I". Выглядит все это следующим образом:
{$I+} - включение вывода ошибок
{$I-} - выключение вывода ошибок
По сути дела отсутствие файла - это ошибка, которая возвращается функцией IOResult. Если же эта функция возвращает 0, то файл успешно открыт, без ошибок. Вот и вырисовывается последовательность действий, необходимых для проверки на наличие файла:
Связываем переменную с файлом;
Выключаем вывод ошибок на экран - {$I-}
Открываем файл необходимой нам процедурой;
Включаем вывод ошибок {$I+} - пусть будет для дальнейшего отслеживания таковых;
Проверяем, если IOResult возвращает нуль, то все было путем и файл открыт. Иначе выводим ошибку.
Вот пример такой программы:
var |
T: Text; |
S: String; |
begin |
Write('Enter filename: '); |
Readln(S); |
Assign(T, S); |
{$I-} |
Reset(T); { открываем файл для чтения } |
{$I+} |
if IOResult <> 0 then { если не нуль, то была ошибка } |
begin |
Write('Error when open file!'); |
Halt; |
end; |
{ иначе все в порядке, продолжаем } |
.......... |
end. |
Закрытие файла
Выше я говорил о том, зачем нужно закрывать файл и когда надо это делать. Закрытие файла производиться с помощью процедуры Close(F), где F - это переменная файлового типа. Эта процедура одна для всех типов файлов.
Запись и чтение файлов. Часть I
Сегодня я хочу рассказать о записи и чтении текствых и типизированных файлов, в следующем выпуске рассказ пойдет о чтении файлов без типа. Итак, переходим к непосредственной обработке файловой информации.
Чтение файлов. Чтение файлов производится с помощью отлично известных нам процедур Read и Readln. Они используются также, как и при чтении информации с клавитуры. Отличие лишь в том, что перед переменной, в которую помещается считанное значение, указывается переменная файлового типа (дескриптор файла):
Read(F, C);
Здесь F - дескриптор файла, C - переменная (Char, String - для текстовых, любого типа - для типизированных файлов).
Также сразу хочу упомянуть о одной, пожалуй самой главной функции при чтении файлов. Это функция поверки на конец файла - Eof(F): Boolean;. В качестве параметра - файловая переменная любого типа. Функция возвращает TRUE если достигнут конец файла и FALSE иначе. Здесь все очень просто, демонстрации ради давайте напишем небольшую программку. Пусть имеем текстовый файл. Давайте его распечатаем и заодно посчитаем, например, количество пробелов:
var |
T: Text; |
С: Char; |
Spaces: Word; |
S: String[79]; { 79-макс. длина пути в DOS } |
begin |
Write('Enter filename: '); |
Readln(S); |
Assign(T, S); |
{ открываем файл для чтения } |
{$I-} |
Reset(T); |
{$I+} |
{ если не нуль, то была ошибка } |
if IOResult <> 0 then |
begin |
Write('Error when open file ', S, ' !'); |
Halt; |
end; |
{ иначе все в порядке, продолжаем } |
{ ЦИКЛ: пока НЕ КОНЕЦ ФАЙЛА } |
While (not Eof(T)) do |
begin |
{ читаем из файла переменную } |
Read(T, C); |
{ если пробел, увеличиваем счетчик } |
If C = ' ' then Inc(Spaces); |
Write(C); |
end; |
Writeln('КОЛИЧЕСТВО ПРОБЕЛОВ: ', Spaces); |
Readln; |
end. |
Думаю, здесь все ясно. Продолжаем двигаться дальше и посмотрим, как производиться запись в файлы.
Запись в файлы. Вы еще не догадались? Запись в файлы производиться точно так же, как и запись на экран - с помощью процедур Write и Writeln. Как и в случае с чтением, перед записываемой в файл переменной указывается тескриптор файла:
Write(F, S);
Здесь F - дескриптор, S - переменная.
При этом, естественно, переменная должна соответствовать типу файла. Примера ради давайте составим еще одну небольшую программку, которая покажет работу с файлами. На сей раз уже используем типизированные файлы, а именно состоящие из чисел. Итак, мы имеем файл, в котором содержаться числа типа Integer. Давайте отсортируем эти числа в файле по возрастанию.
План дейтсвий:
Отрываем типизированный файл из Integer; (проверяем на ошибку и т.п.)
Читаем все числа в массив (считываем, пока не конец файла)
Сортируем массив по возрастанию;
Записываем отсортированный массив обратно в файл.
Получается такая программа:
Program Sorting; |
uses Crt; |
var |
F: File of Integer; |
I, J, M: Word; |
Mas: Array[1..500] of Integer; |
S: String; |
begin |
ClrScr; |
Write('Enter filename: '); |
Readln(S); |
{ открываем файл } |
Assign(F, S); |
{$I-} |
Reset(F); |
{$I+} |
if IOResult <> 0 then |
begin |
Write('Error when open file!'); |
Halt; |
end; |
{ пока не конец файла, читаем массив } |
While (not Eof(F)) do |
begin |
Inc(M); |
Read(F, Mas[M]); |
Write(Mas[M], ' '); |
end; |
{ сортируем массив по возрастанию } |
For I := 1 to M do |
For j := 1 to M do |
if Mas[I] < Mas[J] then |
begin |
inc(mas[j], mas[i]); |
mas[i] := mas[j]-mas[i]; |
dec(mas[j], mas[i]); |
end; |
Writeln; Writeln('============================================='); |
{ перезаписываем файл } |
ReWrite(F); |
For I := 1 to 100 do |
begin |
Write(Mas[I], ' '); |
Write(F, Mas[i]); |
end; |
Writeln; Write('Elements in file: ', M); |
Close(F); |
Readln; |
end. |
Программа очень проста и хорошо демонстрирует работу с типизированными файлами. В качестве сортировки массива я использую метод пузырька, чтобы перезаписать файл использую ReWrite. Вроде не должно возникать никаких сложностей... Будут проблемы, пишите. Ну а на сегодня, пожалуй, все. Этой информации вам будет достаточно, в следующем выпуске займемся, как я уже сказал, нетипизированными файлами и продолжим писать программу "Записная книжка".