Думаю все вы имеете представление о файлах. Сегодня мы научимся работать с ними программно. Что из себя представляет файл? Последовательность из байтов. Давным давно, когда компьютеры были большими :) использовались магнитофонные кассеты для хранения информации. Так вот кассета наглядно представляет собой файл: байты идут друг за другом, как песни. Типа так:
| 0 байт | 1 байт | 2 байт | 3 байт | 4 байт | 5 байт | 6 байт | 7 байт | 8 байт | .... |
Соответственно наша задача на сегодня - научиться читать и писать эти байты. Файл в некотором приближении напоминает массив. Работа с файлом традиционно заключается в следующих действиях:
- открытие файла
- чтение/запись/ничего не делание :)
- закрытие файла
file of типНапример нам нужно описать файл с целыми числами. Тогда мы создадим такой тип:
type
tIntFile = file of integer;
tByteFile = file of byte;
второй тип - это тип для файла из байтов. Создав тип мы соответственно можем создать и файловую переменную:
var
f : tByteFile;
Файловые переменные в корне отличаются от привычных нам. С ними нельзя ничего делать (присваивать значения, сравнивать и т.п.) Файловые переменные используются только в специальных процедурах и функциях для работы с файлами. Итак файловая переменная у нас есть. Теперь нам нужно связать её с файлом. Делается с помощью процедуры:
procedure Assign(var f; String);Первый параметр - это и есть наша файловая переменная. Второй - это имя файла. Имя файла должно соответствовать требованиям операционной системы. Задаётся оно в виде DRIVE:\path\...\name.expansion Здесь (например для файла на диске С в папке bp с именем readme.txt):
- Drive - диск (буквы от A до Z) (у нас это С)
- path - путь (у нас это bp)
- name - имя файла (у нас - readme)
- expansion - расширение (у нас - txt)
- procedure Reset(var F [: File; Recsize: Word ] ); - пока не обращайте внимание на то что находится в квадратных скобках. Для нас процедура выглядит так: procedure Reset (var f);
Открывает файл, связанный с файловой переменной f, для чтения. Если такого файла не существует (не можем же мы читать не существующий файл !) , то возникает ошибка ввода-вывода. Об этой ошибке мы поговорим ниже :) - procedure Rewrite(var F: File [; Recsize: Word ] ); - так же не обращаем внимание на указанное в квадратных скобках.
Эта процедура открывает новый, пустой файл для записи, ему присваивается имя, которое мы указали в вызове Assign. Если файл с таким именем уже существует, то он уничтожается.
procedure Close (var F);Мы обязаны закрыть файл, если мы в него чего-то писали, иначе ничего не сохранится. Вообще закрытие файла, после окончания работы с ним считается одним из правил "хорошего" программирования (с одним правилом вы уже знакомы - не использовать goto). Поэтому мы будем всегда закрывать файл, после работы с ним, даже если мы ничего в него не писали. Тем более, что после закрытия мы можем заново использовать файловую переменную. Вернёмся к ошибке ввода-вывода. Функция:
function IOResult: Integer;возвращает целое число, соответствуешее последней ошибке ввода-вывода (отсюда и название: Input-Output Result - результат ввода-вывода, англ.). Если ошибки нет, соответственно вернёт 0. При этом фунция работает только при выключенном режиме контроля ошибок. Например напишем такую программку:
program test;
type
tfile = file of byte;
var
f : tfile;
begin
assign (f, 'C:\bla.bla'); {связываем f c файлом C:\bla.bla }
reset (f); {пытаемся открыть его для чтения }
writeLn ('Bla-bla-bla!!!') { делаем что-то }
end.
Если у вас нет файла C:\bla.bla то соответственно программа завершится с ошибкой 2 : File not found (файл не найден). Однако такое развитие программы нас (по крайней мере меня) не устраивает. Что же это будет, если программа каждый раз будет завершаться с надписью run time error 2 ??? пользователи явно ничего не поймут. Поэтому нам нужно отключить контроль ошибок ввода-вывода. Итак лезем сюда Options -> Compiler... В появившемся диалоге ищем I/O checking. Если крестик стоит - значит контроль есть, если не стоит - нету. Однако сносить крестик с радостным криком не стоит. Вполне возможно что вам впоследствии понадобится проверка ошибок ввода-вывода. Так что мы пойдём другим путём. Помните, я говорил про штуки которые похожи на комментарии, но таковыми не являются ? Они начинаются с {$ и заканчиваются } похоже на комментарий. Это диррективы компилятору. Мы можем явно указать, где нужна проверка ошибок ввода-вывода, а где нет. Включение проверки ошибок делается с помощью директивы {$I+} выключение - {$I-}. Теперь перепишем нашу программку так:
program test;
type
tfile = file of byte;
var
f : tfile;
begin
{$I-}
assign (f, 'C:\bla.bla');
reset (f);
close (f);
{$I+}
if IOResult = 0 then
writeLn ('bla-bla-bla')
else
writeLn ('file not found')
end.
Теперь можно написать функцию общего назначения, которая проверяет наличие файла, не отключая контроль ошибок для всей программы. При этом выполнение программы не завершится, несмотря на отсутствие файла. Кстати интересная особенность - экран в ДОСе является тоже файлом (файлом ввода и вывода:) Поэтому указав вместо имени файла пустую строку мы получаем доступ к экрану (который у нас и так уже есть :) Теперь переходим к самому интересному - чтению и записи из файла. Для чтения из файла используется уже знакомая нам процедура Read:
procedure Read(F , V1 [, V2,...,Vn ] );Первый параметр f - это файловая переменная, а V1 и т.д. - происходит считывание данных из файла в эти переменные. Переменные должны быть того же типа, что и файл. (т.е. если file of byte, то и Vn должно быть типа byte). При чтении файла, нам нужно проверять не достигнут ли конец ? Концом файла является специальный символ, называемый EOF - EndOfFile (конец файла - англ.). Узнать достигнут ли конец файла, можно вызвав одноимённую функцию:
function Eof(var F): Boolean;F - файловая переменная. Функция возвращает true, если конец файла достигнут и false в противном случае. Таким образом чтение файла нужно производить в цикле - прочитали что-то, проверили не конец ли. Если не конец, тогда прочитали дальше. Например напишем программу для чтения и вывода на экран текстового файла. Для простоты я указал имя C:\autoexec.bat если у вас нет такого файла, то укажите какой-либо другой:
Program readfile;
type
tfile = file of char;
var
f : tfile;
c : char;
begin
assign (f, 'C:\autoexec.bat');
reset (f);
while not EOF (f) do
begin
read (f, c);
write (c)
end;
close (f)
end.
Думая, что вы уже догадываетесь, какую процедуру нужно использовать, для записи в файл. Правильно! write :)
procedure Write(F, V1 [, V2,...,Vn ] );где F - это файловая переменная, а V1 ... Vn - это список переменных, значения которых мы должны записать в файл. Для примера напишем программу, которая копирует один файл в другой. Что нам для этого надо? Считать байт из одного файла - записать байт в другой и так до конца. Сохраним копию autoexec.bat в autoexec.txt:
Program copyfile;
type
tfile = file of byte;
var
fin, fout : tfile;
c : byte;
begin
assign (fin, 'C:\autoexec.bat');
reset (fin);
assign (fout, 'C:\autoexec.txt');
rewrite (fout);
while not EOF (fin) do
begin
read (fin, c);
write (fout, c)
end;
close (fin);
close (fout)
end.
Программа
Думаю понятно, что тип у файла может быть не только предопределённый, но любой созданный нами. Сегодня мы создадим базу данных для учителя :) Она будет содержать имена и оценки учеников. Для каждого ученика создадим запись tstudent с этими данными.
type
tstudent = record
name : string;
result : byte
end;
После этого создадим тип файла, состоящего из таких записей:
tfile = file of tstudent;
после записи в файл мы ради эксперимента подсчитаем число отличников. Для этого нам надо закрыть файл (т.к. мы открыли файл на запись), а потом открыть его на чтение.
Program studentdata;
const
N = 3;
type
tstudent = record
name : string;
result : byte
end;
tfile = file of tstudent;
var
f : tfile;
i : integer;
man : tstudent;
begin
assign (f, 'E:\result.txt');
rewrite (f);
for i := 1 to N do
begin
write ('Введите имя: ');
readLn (man.name);
write ('Введите оценку: ');
readLn (man.result);
write (f, man)
end;
close (f);
reset (f);
i := 0;
while not EOF (f) do
begin
read (f, man);
if man.result = 5 then
i := i + 1
end;
writeLn ('Число отличников: ', i);
close (f)
end.
думаю, что текст программы довольно прозрачен.

