Nickolay.info. Обучение. Учебник по Паскалю. Глава 21

21. Текстовые файлы

 

Для написания большинства сложных программ требуется обмен данными с файлами. В этой главе мы рассмотрим только текстовые файлы, для работы с бинарными и типизированными файлами см. специальную литературу и гл. 22.

 

21.1. Общие операции

 

Для работы с каждым файлом описывается переменная типа 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.

Этой учебной программе недостает как умения редактировать открываемый ей справочник, так и гибкости при поиске -- например, она различает как разные символы  строчные и прописные буквы во вводимой фамилии.

 

21.2. Примеры работы с файлами

 

Рассмотрим несколько типовых задач на обработку текстовых файлов.

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;

Приведенный пример иллюстрирует, как часто выбор программистом более или менее удобного формата хранения данных влияет на сложность программы.

 

21.3. Работа с параметрами командной строки

 

Программа в 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.

Рейтинг@Mail.ru
вверх гостевая; E-mail