Pers.narod.ru. Обучение. Учебник по Паскалю. Глава 21 |
Для написания большинства сложных программ требуется обмен данными с файлами. В этой главе мы рассмотрим только текстовые файлы, для работы с бинарными и типизированными файлами см. специальную литературу и гл. 22.
Для работы с каждым файлом описывается переменная типа text:
var f:text;
Ее называют файловой переменной. Если программа обрабатывает несколько файлов одновременно, для каждого из них описывается такая переменная. Можно использовать и одну переменную для нескольких файлов, если они обрабатываются последовательно, и каждый следующий файл открывается после завершения работы с предыдущим. Вся работа с файлом происходит через файловую переменную, имя файла указывается только один раз следующим оператором:
assign (f,'имя_файла');
где f -- ранее описанная файловая переменная.
Этот оператор предшествует открытию файла и связывает переменную с файлом на жестком или гибком диске. В качестве имени файла может быть указан абсолютный или относительный путь к файлу на жестком или сменном диске:
assign (f,'data.txt');
-- будет открываться файл с именем data.txt из текущей папки;
assign (f,'a:\my.dat');
-- будет открыт файл с именем my.dat из корневой папки дискеты.
Имя файла также может быть введено пользователем с клавиатуры:
var name:string; f:text;
begin
writeln ('Введите имя файла:');
readln (name);
assign (f,name);
.
Наконец, имя файла можно передать программе параметром командной строки (см. п. 5.3).
После связывания следует открыть файл. Каждый файл может быть открыт только в одном из трех режимов -- для чтения данных, для записи новых данных (при этом, если файл уже существовал, его прежнее содержимое будет стерто) или для добавления данных в конец файла. Если требуется сначала прочитать данные из файла, а потом переписать этот же файл, следует открыть файл для чтения, после чтения закрыть его и вновь открыть для записи. Открытие файла выполняется одним из трех операторов:
reset (f); -- открыть для чтения;
rewrite (f); -- открыть для записи;
append (f); -- открыть для добавления.
Чтение или запись данных осуществляется знакомыми нам операторами read, readln, write и writeln, но первым параметром этих стандартных процедур указывается имя файловой переменной:
var a,b,c:real; f1,f2:text;
begin
assign (f1,'read.txt');
assign (f2,'write.txt');
reset (f1);
{открыли файл read.txt для чтения,}
rewrite (f2);
{а файл write.txt для записи}
read (f1,a,b);
{Прочитали 2 числа из файла read.txt}
c:=(a+b)/2;
writeln (f2,c:6:2); {записали значение c
и перевод строки в файл write.txt}
После того, как все операции с файлом выполнены, его следует закрыть, особенно если происходила запись или добавление данных:
close(f);
- закрыли файл, связанный с файловой переменной f.
При работе с файлами могут возникнуть ошибки, связанные как с отсутствием нужного файла на диске, так и с проблемами чтения или записи (например, мы пытаемся открыть файл для записи на защищенном диске). Поэтому операторы открытия файла и чтения или записи данных следует защищать директивой компилятора {$I-}...{$I+}, а после оператора проверять статус операции ввода-вывода с помощью стандартной функции IoResult:
var f:text; name,s:string;
begin
writeln ('Введите имя файла:');
readln (name);
assign (f,name);
{$I-}reset(f);{$I+}
if IoResult<>0 then begin
writeln ('Не могу открыть файл ',name,
' для чтения!');
writeln ('Нажмите Enter для выхода');
readln;
halt;
end;
readln(f,s);
writeln ('Первая строка файла:');
writeln (s);
close(f);
writeln ('Нажмите Enter для выхода');
readln; end.
В дальнейшем мы для краткости не всегда будем выполнять эти проверки, но хороший стиль программирования предполагает, что в своих программах вы будете их делать.
При чтении из файлов зачастую объем читаемых данных неизвестен заранее. Поэтому необходима функция, умеющая определять, прочитаны ли уже все данные:
function Eof(var F : text) : boolean;
-- возвращает true, если при чтении достигнут конец файла.
function Eoln (var F : text) : boolean;
-- возвращает true, если при чтении достигнут конец строки.
Как правило, основной цикл чтения файла с заранее неизвестным количеством строк выглядит так:
while not eof (f) do begin
{операторы для чтения строк файла
и работы с ними}
end;
При чтении из одного файла "смешанных" строковых и числовых данных следует проверять, действительно ли в нужных строках файла содержатся числа. Для этого можно использовать стандартную процедуру val. Как правило, формат файлов, понимаемых той или иной программой, выбирается программистом, и важно предусмотреть реакцию программы на ошибочный формат исходных данных. Допустим, наша программа представляет собой простейший телефонный справочник, включающий имена абонентов и по одному телефонному номеру на каждое имя. Формат файла, хранящего данные справочника, также выберем простейшим:
Фамилия1
Номер1
Фамилия2
Номер2
и т. д., то есть, в строках 1, 3, 5, ... файла содержатся фамилии абонентов, а в строках 2, 4, 6, ... -- их номера телефонов. Примем также, что файл справочника называется phones.txt, существует и находится в той же папке, откуда запускается программа. Полный листинг программы приводится ниже.
var f:text;
name,phone,search:string;
number,strings:longint;
error:integer;
found:boolean;
begin
assign (f,'phones.txt');
reset(f);
writeln (Фамилия абонента для поиска:');
readln (search);
strings:=1; {Счетчик прочитанных строк}
found:=false; {Переключатель
"найдено"-"не найдено"}
while not eof(f) do begin
readln (f,name); {Прочитали фамилию}
readln (f,phone); {Прочитали номер}
val (phone,number,error); {Пробуем
номер-строку преобразовать в число}
if error<>0 then begin {если это
не удалось сделать - ошибка}
writeln('Ошибка - нет номера телефона!',
' Номер строки=', strings);
writeln ('Нажмите Enter для выхода');
reset (input); readln; halt;
end;
if name=search then begin
writeln ('Телефон найден:',number);
found:=true;
break;
end;
strings:=strings+1;
end;
close (f);
if found=false then
writeln ('Телефон не найден!');
writeln ('Нажмите Enter для выхода');
reset (input); readln;
end.
Этой учебной программе недостает как умения редактировать открываемый ей справочник, так и гибкости при поиске -- например, она различает как разные символы строчные и прописные буквы во вводимой фамилии.
Рассмотрим несколько типовых задач на обработку текстовых файлов.
1. Чтение числовых данных из файла. Массив данных имеет фиксированную размерность, примем ее равной 5.
var f,w:text;
a: array [1..5] of integer; i:integer;
begin
assign (f,'data.txt');
reset (f);
for i:=1 to 5 do read (f, a[i]);
close (f);
assign (w, 'result.dat');
rewrite (w);
writeln (w,'Результаты:');
for i:=1 to 5 do
writeln (w,a[i]:5,sqr(a[i]):5);
close(w); end.
Файл с именем data.txt может быть, например, таким:
1 2 3
4 5
Файл результатов result.dat будет таким:
Результаты:
1 1
2 4
3 9
4 16
5 25
2. Просмотр любого текстового файла на экране. По заполнении экрана до 24 строк программа делает паузу.
var f:text; s:string; count:integer;
begin
repeat
write ('Имя файла или 0 для выхода: ');
readln (s);
if s='0' then halt;
assign (f,s);
{$I-}reset (f);{$I+}
if IoResult<>0 then begin
writeln ('Не могу открыть файл ',s);
write ('Нажмите Enter для продолжения');
readln;
continue; {повторяем цикл с начала}
end;
count:=1;
while not eof(f) do begin
readln (f,s);
writeln (s);
count:=count+1;
if count=24 then begin
count:=1;
write('Нажмите Enter для продолжения');
readln;
end;
end;
write ('Нажмите Enter для нового ввода');
readln;
close (f);
until false;
end.
Строка s здесь используется как для ввода имени файла, так и для чтения строки файла -- ведь после выполнения связывания оператором assign имя файла нам больше не нужно. Обратите внимание также на оператор continue, в данном случае он позволяет не завершать выполнение программы после неверного ввода пользователя.
3. Работаем со "смешанным" файлом данных, строки которого содержат значения разных типов.
Пусть файл data.txt имеет следующий вид:
Иванов 2
Петров 1
Сидоров 3
Попов 2
...
В каждой строке файла находится фамилия рабочего и через пробел -- номер участка, на котором он работает.
Напишем программу для вывода фамилий всех работников выбранного участка и подсчета их количества.
var f:text; s,fam:string;
u,uch,p,kol,i:integer;
begin
writeln ('Участок?'); read (uch);
assign (f,'data.txt'); reset (f);
kol:=0;
while not eof (f) do begin
readln (f,s);
p:=pos(' ',s);
if p>0 then begin
fam:=copy (s,1,p-1);
delete (s,1,p);
val (s,u,i);
if i<>0 then begin
writeln ('Ошибка в числе ',s,
' - нет номера участка');
halt;
end;
if u=uch then begin
{подсчет рабочих на участке}
writeln (fam);
kol:=kol+1;
end;
end
else begin
writeln ('Ошибка в строке ',s,
' - нет пробела');
halt;
end;
end;
close (f);
writeln ('kol=',kol);
end.
Значительная часть этой программы посвящена анализу прочитанной из файла строки "смешанных" данных. Программу можно существенно упростить, изменив формат исходных данных -- например, на одной строке файла может быть набрана фамилия, а на другой -- номер участка. Тогда основной цикл чтения файла будет выглядеть так:
while not eof (f) do begin
readln (f,fam);
readln (f,u);
if (u=uch) then begin
{ обработка }
end;
end;
Приведенный пример иллюстрирует, как часто выбор программистом более или менее удобного формата хранения данных влияет на сложность программы.
Программа в DOS или Windows может запускаться с параметрами командной строки, через которые обычно передают имена файлов или указывают режимы работы программы:
turbo.exe vasya.pas
- здесь программе Турбо Паскаль передано имя файла vasya.pas;
my /s /a
- программе с именем my переданы параметры /s и /a.
Существует две стандартных функции для работы с параметрами:
Paramcount -- вернет общее число параметров командной строки;
Paramstr(i) -- вернет строку, содержащую параметр номер i.
В качестве примера реализуем программу просмотра текстового файла на экране, которой параметром передается имя нужного файла.
var fil:text; name:string;
begin
if Paramcount<>1 then begin
writeln ('Запускайте так: ',
'FILEVIEW имя_файла');
halt; end;
assign (fil,Paramstr(1));
reset (fil);
while not eof(fil) do begin
readln (fil,name);
writeln (name);
end;
end.
Второе полезное свойство функции Paramstr -- вызванная из исполняемого файла с аргументом 0, она возвращает полный путь к нему.
Из оболочки Турбо Паскаля параметры командной строки можно передать запускаемой программе через пункт Parameters меню Run.
гостевая; E-mail |