Учебник по программированию.

Первые шаги. Язык программирования PascalABC.

Предыдущий параграф Назад в содержание Следующий параграф


§12. Файлы.

Мы многое узнали и многому научились. Сейчас возникает естественная потребность в обработке больших объёмов информации и в том, что бы сохранять результаты работы программы. Если вы хоть немного владеете, как пользователь, компьютером, то вы, конечно, скажете, что это можно реализовать с помощью файлов.

Под словом файл мы будем понимать совокупность данных расположенных на жёстком диске компьютера. Сейчас мы не будем вдаваться в подробности, как устроена файловая система, и как осуществляется хранение информации на жёстком диске. Всё это скрыто от программиста Pascal-ем и операционной системой.

Для того, что бы работать с файлом в Pascal, необходимо создать переменную типа файл или другими словами файловую переменную. Все операции с файлами осуществляются через эту переменную. Не надо думать, что эта переменная и есть файл. Эта переменная является указателем на реальный файл. Когда вы будете вызывать какую-либо процедуру или функцию работы с файлом, вы будете в качестве параметра использовать файловую переменную, которая будет указывать процедуре или функции с каким именно файлом необходимо работать.

В Pascal существует три вида файлов это: типизированные, текстовые файлы и нетипизированные. Перед тем, как начать их изучать поговорим об именах файлов.


Имена файлов.

Имя файла это строка, состоящая из любой последовательности символов. В именах файлов разрешено использовать не все символы. К разрешённым относятся все буквы, цифры и ряд символов: «! @ # $ % ^ & ( ) ' ` ~ - _ . ,», а также можно использовать пробел, в том случае если есть другие символы.

Обычно в имени файла содержится расширение, которое находится в конце имени и отделяется от него точкой. На практике расширение необходимо для того, что бы было понятно, что это за файл. Это может быть исполняемый файл т.е. программа (расширение .exe), или это файл какой-либо программы, например документ Microsoft Word (расширение .docx). Когда будете придумывать расширение, постарайтесь что бы оно что-либо обозначало.

Так же имя файла может содержать в себе полный путь, т.е. местоположение файла. Полный путь начинается с имени диска или устройства, на котором находится файл. Имена дисков или устройств состоят из одной буквы латинского алфавита. Как правило, буквы «A» и «B» зарезервированы под дисководы, которые на данный момент уже устарели и практически не используются. Далее идёт диск «C» это обычно раздел жёсткого диска, на котором, как правило, установлена операционная система. Если жесткий диск имеет более одного раздела, то эти разделы будут называться следующими по алфавиту символами. Потом даётся имя CD-DVD-рому. Затем имя может получить флешка.

После буквы устройства, на котором находится файл, ставиться двоеточие и косая черта «\». Затем идут названия каталогов, в которых находится файл. Названия каталогов разделяются косой чертой «\». Например, имя файла может быть следующим:


«c:\Windows\Media\chord.wav».


Типизированные файлы.

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

Для создания файловой переменной, которая будет указывать на типизированный файл, используется словосочетание file of, после которого указывается тип данных, которые будут содержаться в файле, например:


var f:file of integer;


Так же можно, в начале, создать свой тип, а затем создать переменную этого типа:


Type Tf = file of integer;

var f:Tf;


Далее необходимо связать файловую переменную с файлом, на который она будет указывать. Делается это с помощью процедуры assign:


assign(f,'c:\111111.int');


В скобках первым параметром идёт файловая переменная, вторым строка, которая содержит в себе имя файла. С помощью процедуры Assign мы связали файловую переменную с реальным файлом. Причём самого файла на момент вызова процедуры assign может ещё и не существовать. Просто процедура assign связывает файловую переменную и имя файла, а так же путь к нему.

Далее для того, что бы создать реальный файл необходимо вызвать процедуру rewrite(f). При этом будет создан новый пустой файл, причём если файл с таким именем уже существовал, то он будет удалён. Т.е. процедура rewrite создаёт новый файл, на который указывает файловая переменная:


  rewrite(f);


После того, как был создан новый файл, в него можно записывать данные с помощью уже знакомой нам процедуры write. Причём первым параметром должна находиться файловая переменная, а затем через запятую перечисляются переменные или константы, которые необходимо записать в файл. Причём эти константы и переменные должны быть того типа, который указан при объявлении файловой переменной:


  write(f,3,4,5,6);


Что бы считать данные из файла используется, знакомая нам процедура, read, причём первым параметром должна идти файловая переменная, а затем через запятую переменные, в которые должны быть записаны данные из файла:


  read(f,a,b,c,d);


Когда работа с файлом закончена, его необходимо обязательно закрыть, иначе при завершении работы программы, если файл остался открытым, могут возникнуть проблемы в файловой системе жёсткого диска. Закрывается файл с помощью процедуры Close(f):


  close(f);


Если необходимо открыть уже существующий файл, не удалив его, используется процедура Reset(f):


  reset(f);


Теперь пример целой программы:


Type Tf = file of integer;

var f:Tf;

    a,b,c,d:integer;

begin

  assign(f,'c:\111111.int');

  rewrite(f);

  write(f,3,4,5,6);

  close(f);

  reset(f);

  read(f,a,b,c,d);

  writeln(a,b,c,d);

  close(f);

end.

_____________________________

3456


В данном примере запись и чтение данных происходит по порядку. Иногда приходится считывать данные из какого-либо места в файле. Для этого существует следующее понятие: файловый указатель. При открытии  или создании файла файловый указатель устанавливается в начало файла и указывает позицию 0. Когда мы записываем данные в файл, после записи каждого элемента файловый указатель перемещается на одну позицию. При чтении данных происходит то же самое, после чтения каждого элемента файловый указатель перемещается на одну позицию вперёд.

Для работы с файловым указателем существуют следующие процедуры и функции:

procedure Seek(f: file of T; n: LongInt);

Устанавливает текущую позицию файлового указателя в типизированном файле f на элемент с номером n.

function FilePos(f: file of T): LongInt;

Возвращает текущую позицию файлового указателя в типизированном файле f.

function FileSize(f: file of T): LongInt;

Возвращает количество элементов в типизированном файле f.

Пример:


Type Tf = file of integer;

var f:Tf;

    a,b,c,d:integer;

begin

  assign(f,'c:\111111.int');

  reset(f);

  seek(f,2);            read(f,c);

  seek(f,filepos(f)-3); read(f,a);

  seek(f,filesize(f)-1);read(f,d);

  seek(f,1);            read(f,b);

  close(f);

  writeln(a,b,c,d);

end.

__________________________________

3456


В этом примере чтение данных из файла мы произвели не по порядку, используя процедуры и функции для работы с файловым указателем. Так же стоит сделать следующие замечания: как уже было сказано, первый элемент имеет нулевую позицию, соответственно второй элемент первую позицию и т.д. отсюда, что бы считать или записать первый элемент файловый указатель необходимо поставить в нулевую позицию, второй элемент в первую и т.д. Стоит ещё добавить, что номер позиции последнего элементы будет равен количеству элементов в файле за вычетом единицы. И ещё одно, прежде чем считывать данные из файла, рекомендую всегда устанавливать файловый указатель в нужную позицию.

Записывать элементы в файл можно так же не по порядку, используя процедуры и функции для работы с файловым указателем. Если взять предыдущий пример, то просто вместо процедуры read подставить процедуру write. Как уже было сказано выше, при записи элемента файловый указатель смещается на одну позицию, при этом происходит стирание старого элемента и запись нового в то место, где находился файловый указатель.

Для чтения всех данных из файла, удобно пользоваться следующей функцией:

function Eof(f: FileType): boolean;

Возвращает True, если файловый указатель находится в конце файла f. Данная функция применима ко всем трём типам файлов. Пример:


Type Tf = file of integer;

var f:Tf;

    temp:integer;

begin

  assign(f,'c:\111111.int');

  reset(f);

  While not eof(f) do

   begin

     read(f,temp);

     write(temp);

   end

  close(f);

end.

____________________________

3456


Далее приведу ещё ряд процедур и функций для работы с типизированными файлами:

function FilePos(f: file of T): LongInt;

Возвращает текущую позицию файлового указателя в типизированном файле f. Иногда возникает необходимость узнать текущую позицию файлового указателя. Например, если вы пишете не всю программу целиком, а какую-то подпрограмму, и при выходе из вашей подпрограммы файловый указатель необходимо вернуть в прежнее место:


var f:file of integer;

    a,c:integer;


Procedure VivodFila;

var pos:longint;

    temp:integer;

begin

  pos:=filepos(f);

  seek(f,0);

  While not eof(f) do

   begin

     read(f,temp);

     write(temp,' ');

   end

  seek(f,pos);

end;


begin

  assign(f,'c:\111111.int');

  reset(f);

  seek(f,2);

  VivodFila;

  writeln;

  read(f,a,c);

  writeln(a,'+',c,'=',a+c);

  close(f);

end.

____________________________

20 4 30 40

30+40=70


procedure Truncate(f: file of T);

Усекает типизированный файл f, отбрасывая все элементы с позиции файлового указателя.


var f:file of integer;

Procedure VivodFila;

//Процедура VivodFila описана в одном из предыдущих примеров

........................

begin

  assign(f,'c:\1234');

  rewrite(f);

  write(f,1,2,3,4,5,6);

  vivodFila;

  writeln;

  seek(f,3);

  Truncate(f);

  vivodFila;

  close(f);

end.

_______________________

1 2 3 4 5 6

1 2 3


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

Когда речь начинала идти о типизированных файлах, было сказано, что типизированные файлы не могут содержать в себе строки переменной длины. Для того, что бы записывать в файл строки переменной длины существуют текстовые файлы. Как и с любыми файлами, работа с текстовыми файлами осуществляется через файловую переменную. Для объявления файловой переменной текстового файла используется слово Text:


Var f:text;


Аналогично типизированным файлам, необходимо связать файловую переменную с файлом с помощью процедуры Assign(f). После работы с файлом его необходимо закрыть процедурой close(f).

В отличие от типизированных файлов чтение и запись в текстовый файл происходит целиком. Нельзя записать данные в какое-либо место файла или считать данные из какого либо места. Поэтому для текстовых файлов процедура rewrite(f) создаёт новый файл, стирая старый, только для записи в него. Процедура reset(f) открывает текстовый файл только для чтения.

Чтение и запись данных в текстовый файл осуществляется с помощью, до боли знакомых нам, процедур Write, Writeln, Read, Readln. Так же первым параметром идёт файловая переменная, затем список через запятую констант или переменных (параметров).

Прежде чем  вести речь о том, как пользоваться этими процедурами, необходимо узнать структуру тестового файла. Текстовый файл состоит из строк переменной длины. В конце каждой строки находится специальное сочетание символов с порядковыми номерами 13 и 10. Например, если мы добавим данное сочетание в середину строки, то при выводе на экран в этом месте строка разорвётся и текст начнётся с новой строки:


var s:string;

begin

  s:='Привет'+chr(13)+chr(10)+'всем!';

  write(s);

end.

______________________________________

Привет

всем!


Наглядно структуру текстового файла можно продемонстрировать следующим образом:


……………………#13#10

……………#13#10

…………………………………#13#10

…#13#10

Eof


В данном примере: Eof признак конца файла, который присутствует в любом файле. Символ «#» говорит о том, что на этом месте находится символ с порядковым номером, который идёт далее.

Теперь можно говорить о процедурах чтения и записи.

Процедура Write делает запись в текстовый файл, но не вставляет комбинацию символов #13#10. Следовательно, при записи данных с помощью только этой процедуры в текстовом файле окажется только одна строка.

Процедура Writeln делает запись в текстовый файл и вставляет комбинацию символов #13#10. Следовательно, после вызова данной процедуры вставляется признак конца строки, и следующая запись будет происходить в новую строку.

Процедура Read считывает данные из файла, но не делает переход на следующую строку. Что бы считать данные и перейти на следующую строку необходимо использовать процедуру Readln.

Пример:


var f:text;

    s:string;

begin

  assign(f,'c:\text.txt');

  rewrite(f);

  write (f,'Привет');//Записываем строку в файл

  Writeln(f,' всем!');//Записываем строку в файл и переходим на следующую

  writeln(f,'Ура, ура!');//Записываем строку в файл и переходим на

                         //следующую

  close(f);

  reset(f);

  read(f,s);//считываем строку

  writeln(s);

  readln(f);//переходим на следующую строку

  readln(f,s);//считываем строку и переходим на следующую

  writeln(s);

end.

_________________________________________________________________________

Привет всем!

Ура, ура!


Данными процедурам можно записывать в текстовый файл не только строки, но и символы, т.е. данные типа char. Ни каких тонкостей и нюансов при этом нет, происходит это так же как и со строками.

Так же вместо строк и символов можно записывать числа целые и вещественные, при этом они автоматически будут форматироваться в строку для записи и обратно для чтения. Только будьте внимательны и следите за соответствием данных:


var f:text;

    i:integer;

    r:real;

begin

  assign(f,'c:\text.txt');

  rewrite(f);

  writeln (f,12);

  Writeln(f,3.14);

  close(f);

  reset(f);

  readln(f,i);

  writeln(i);

  readln(f,r);

  writeln(r);

end.

_________________________

12

3.14


Так же в текстовый файл можно вписать множество, однако считать его можно будет только как строку:


const m:set of integer = [3..4,6,55..57];

var f:text;

    s:string;

begin

  assign(f,'c:\text.txt');

  rewrite(f);

  writeln (f,m);

  close(f);

  reset(f);

  readln(f,s);

  writeln(s);

  close(f);

end.

_________________________________________

[3,4,6,55,56,57]


Для того, что бы целиком считать текстовый файл удобно пользоваться уже знакомой нам функцией Eof:


var f:text;

    i:integer;

    s:string;

begin

  assign(f,'c:\text.txt');

  rewrite(f);

//Создаем файл случайной длины со случайными значениями

  For i:=1 to random(50) do

    begin

     write (f,random(1000):4,' ');

     if i mod 10 = 0 then writeln(f);

    end;

  close(f);

//Выводим содержимое файла на экран

  reset(f);

  while not eof(f) do

    begin

     readln(f,s);

     writeln(s);

    end;

  close(f);

end.

_________________________________________________________

420  562  614  705  959  901  757  734  115  238

389  307  599  625  981  906  682  865  597  934

127  300  324  747  806  814  559  175  837  759

478  490  827  424  346  819  285  726


И ещё одна специфическая процедура для работы с текстовыми файлами: Append(f) открывает текстовый файл для дополнения, т.е. после открытия файла данной процедурой можно вписывать в него данные, при этом старое содержимое стёрто не будет, а запись будет происходить с того места, где файл был закончен. Поэтому если хотите начать запись с новой строчки, то возможно понадобиться добавить признак конца строки:


var f:text;

    i:integer;

    s:string;

begin

  assign(f,'c:\text.txt');

//Открываем файл для дополнения

  Append(f);

  writeln(f,chr(13),chr(10),'Всё это случайные числа');

  close(f);

//Выводим содержимое файла на экран

  reset(f);

  while not eof(f) do

    begin

     readln(f,s);

     writeln(s);

    end;

  close(f);

end.

________________________________________________________

420  562  614  705  959  901  757  734  115  238

389  307  599  625  981  906  682  865  597  934

127  300  324  747  806  814  559  175  837  759

478  490  827  424  346  819  285  726

Всё это случайные числа


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


Задачи.

1. Необходимо создать массив случайных целых чисел, записать его в файл, затем вывести его на экран из файла.

2. Создать с помощью программы текстовый файл (не менее 2-х строк). Добавить в него ещё одну строку с помощью процедуры Append. Вывести файл на экран.

3. Создать программу поиска слова в текстовом файле. Слово для поиска пользователь вводит с клавиатуры. Примечание: в предыдущем параграфе в 3-ей задаче необходимо было вывести в отдельную функцию процесс поиска слова в строке. При создании программы можно использовать данную функцию.

4. Написать функцию определения количества строк в текстовом файле. Написать функцию, считывающую определённую строку по номеру из текстового файла. Написать программу демонстрирующую работу данных подпрограмм.

5. Имеется текстовый файл со списком слов. Каждое слово находится в новой строчке. Необходимо отсортировать слова по алфавиту. Регистр букв не должен иметь значения. Примечание: для примера создать список не менее 20 слов.


Решение.

1.

Program Ispolzovanie_Massiva;

//Программа демонстрирует работу с типизированными файлами


const imya_file = 'c:\massiv.int';//Константа содержит название файла

      max = 30;// размер массива

var massiv: array [1..max] of integer;

    f:file of integer;

    i:integer;


begin

  //Заполняем массив

  for i:=1 to max do

    massiv[i]:=random(1,1000);


  //Записываем в файл

  assign(f,imya_file);

  rewrite(f);

  for i:=1 to max do

    write(f,massiv[i]);

  close(f); 

 

  //Читаем массив из файла

  assign(f,imya_file);

  reset(f);

  for i:=1 to max do

    read(f,massiv[i]);

  close(f); 


  //Выводим массив на экран

  for i:=1 to max do

    begin

      write(massiv[i]:5);

      if (i mod 10)=0 then writeln;//Создаем новую строчку

    end;

end.

_________________________________________________________________________

  920  288  950  972  812  413  244  579  112  357

  513  855  943  299  292  694   51  976  309  973

  457  561   45  855  308  284  511  119  146  809


2.

Program Sozdanie_textovogo_fayla;

//Программа создаёт текстовый файл, дополняет его и выводит его на экран

Var f:text;

    s:string;

Begin

//Создаём текстовый файл

  assign(f,'c:\Text.txt');

  Rewrite(f);

  writeln(f,

     'В классе 20 учеников. Все ученики учатся по-разному. Одни ученики '+

     'являются отличниками или хорошистами, другие ученики троечники, учеников'+

     ' двоечников нет.');

  Writeln(f,'В другом классе 22 ученика. Двоечников учеников тоже нет.');

  close(f);

//Добавляем в текстовый файл строку

  Append(f);

  Writeln(f,'Всего в школе есть один ученик двоечник.');

  close(f);

//Выводим текстовый файл на экран

  reset(f);

  while not eof(f) do

    begin

      readln(f,s);

      writeln(s);

    end;

  close(f);

end.

_________________________________________________________________________

В классе 20 учеников. Все ученики учатся по-разному. Одни ученики являются отличниками или хорошистами, другие ученики троечники, учеников двоечников нет.

В другом классе 22 ученика. Двоечников учеников тоже нет.

Всего в школе есть один ученик двоечник.


3.

Program Poisk_slova_v_fayle;

//Программа ищет слово в файле и выводит, сколько раз это слово встречается


Const imya_fayla = 'c:\Text.txt';//файл в котором будем искать


Var f:text;   //файловая переменная

    sTemp,    //Переменная для хранения текущей строки

    s         //Переменная для хранения слова для поиска

    :string;

    kolTek,   //количество найденных слов в текущей строке

    kol       //количество найденных слов в файле

    :integer;


//Функция находит количество слов s2, входящих в строку s1

Function Poisc(s1,s2:string):word;

var i,s:word;

begin

s:=0;

i:=1;

while i<length(s1)do

   begin

    if (PosEx(s2,s1,i)<>0)then

      begin

        s:=s+1;

        i:=PosEx(s2,s1,i);

      end;

      i:=i+1;

   end;

  Poisc:=s;

end;


begin

  Writeln('Введите слово для поиска');

  readln(s);

  assign(f,imya_fayla);

  reset(f);

  //======================================

  //ищем слово в файле

  kol:=0;

  while not eof(f) do

    begin

      readln(f,sTemp);

      kolTek:=poisc(sTemp,s);

      if kolTek <> 0 then kol:=kol+kolTek;

    end;

  //======================================

  close(f);

  Writeln;

  Write('В текстовом файле "',imya_fayla,'" слово "',s,'" ');

  if kol<>0 then write('встречается ',kol,' раз.')

   else write('невстречается.');

end.

______________________________________________________________

Введите слово для поиска

ученик


В текстовом файле "c:\Text.txt" слово "ученик" встречается 8 раз.


4.

Program Textovie_fayli;

//Программа содержит функцию выдающую количесвто строк в текстовом файле

//и функцию выдающую строку из файла по номеру

var kol_strok_v_fayle:integer; //содержит количество строк в файле

    nomer_stroki:integer;      //Номер строки для вывода

    sn:string;                 //строка для вывода по номеру


//Функция определения количества строк в текстовом файле imya_fayla

function kol_strok(imya_fayla:string):integer;

var f:text;

    kol:integer;

begin

  kol:=0;

  assign(f,imya_fayla);

  reset(f);

  while not eof(f) do

    begin

      inc(kol);

      readln(f);

    end;

  kol_strok:=kol;

  close(f);

end;


//Функция выдаёт строку из файла imya_fayla по её номеру n.

function stroka_po_nomeru(imya_fayla:string;n:integer):string;

var f:text;

    i:integer;

    sTemp:string;

begin

  assign(f,imya_fayla);

  reset(f);

  for i:=1 to n do readln(f,sTemp);

  stroka_po_nomeru:=sTemp;

  close(f);

end;

   

begin

  //Определяем количесвто строк в файле

  kol_strok_v_fayle:=kol_strok('c:\Text.txt');

  writeln('В текстовом файле "c:\Text.txt" содержится ',

                                kol_strok_v_fayle,' строк.');

 

  //Выводим строку по её номеру

  writeln('Введите номер строки для вывода.');

  readln(nomer_stroki);

  If kol_strok_v_fayle < nomer_stroki then

     writeln('В данном текстовом файле строки с таким номером нет.')

   else

     begin

       sn:=stroka_po_nomeru('c:\Text.txt',nomer_stroki);

       write('Строка с номером ',nomer_stroki,

          ' содержит в себе следующее: "',sn,'"');

     end;

end.

_________________________________________________________________________

В текстовом файле "c:\Text.txt" содержится 3 строк.

Введите номер строки для вывода.

2

Строка с номером 2 содержит в себе следующее: "В другом классе 22 ученика. Двоечников учеников тоже нет."


5.

Program Sortirovka_slov;

//Программа сортирует список слов в текстовом файле по алфавиту

var f,fTemp:text;

    sTemp,//Строка для временного хранения

    s1,s2,//Предыдущая и следующая строки соответственно

    s11,s22//Предыдущая и следующая строки соответственно в нижнем регистре

    :string;

    flg:boolean;//Если слова уже отсортированы то равна false

//Процедура для вывода списка на экран

Procedure vivod_spiska_iz_fayla;

begin

  reset(f);

  while not eof(f) do

    begin

      readln(f,sTemp);

      write(sTemp);

      if eof(f) then write('.') else write(', '); 

    end

   Writeln;

   close(f);

end;


begin

  assign(f,'c:\Список.txt');

  assign(fTemp,'c:\Temp.txt');

  write('Имеем следующий список: ');

  vivod_spiska_iz_fayla;

//Сортируем список

  flg:=true;//Список ещё не отсортирован

  while flg do

   begin

     reset(f);

     readln(f,s1);

     rewrite(fTemp);

     flg:=false;//Если список уже отсортирован, то далее в True не установтся

     While not eof(f) do

       begin

        readln(f,s2);

      //Переводим строки в нижний регистр 

        s11:=LowerCase(s1);

        s22:=LowerCase(s2);

   //Если в нижнем регистре предыдущая строка больше следующей строки, то

   //меняем строки местами и устанавливаем flg в true

        if s11>s22 then

          begin

            flg:=true;

            sTemp:=s1;

            s1:=s2;

            s2:=Stemp;

          end;

        writeln(fTemp,s1);//Записываем во временный файл

        s1:=s2;

       end

     writeln(fTemp,s2);//Дописываем последнюю строку

     close(f);

     close(fTemp);

   //Заменяем исходный файл временным

     erase(f);

     rename(fTemp,'c:\Список.txt');

   end;

  writeln;

  write('После сортировки: ');

  vivod_spiska_iz_fayla;

end.

_________________________________________________________________________

Имеем следующий список: пища, Несъедобное, единственный, выход, можно, более, незаметно, посторонний, предмет, Рот, палец, краешек, тарелка, Это, Волосок, масло, червяк, лист, салат, муха.


После сортировки: более, Волосок, выход, единственный, краешек, лист, масло, можно, муха, незаметно, Несъедобное, палец, пища, посторонний, предмет, Рот, салат, тарелка, червяк, Это.




Предыдущий параграф Назад в содержание Следующий параграф