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

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

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


§13. Нетипизированные файлы. Подпрограммы для работы с файлами.

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

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

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


var f:file;

    s:string;

    b:integer;

    r:real;

begin

  assign(f,'c:\file.dat');

  rewrite(f);

  write(f,'Иван');

  write(f,'Иванович');

  write(f,'Иванов');

  Write(f,30);

  Write(f,'Помощник директора');

  Write(f,35600.35);

  close(f);

  reset(f);

  read(f,s);

  Writeln('      Имя - ',s);

  read(f,s);

  Writeln(' Отчество - ',s);

  read(f,s);

  Writeln('  Фамилия - ',s);

  read(f,b);

  Writeln('  Возраст - ',b,' лет');

  read(f,s);

  writeln('Должность - ',s);

  read(f,r);

  Writeln('    Доход - ',r,' рублей в месяц');

  close(f);

end.

________________________________________________

      Имя - Иван

Отчество - Иванович

  Фамилия - Иванов

  Возраст - 30 лет

Должность - Помощник директора

    Доход - 35600.35 рублей в месяц


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

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

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

function Eof(f: FileType): boolean; Возвращает True, если достигнут конец файла f.

procedure Truncate(f: file); Усекает нетипизированный файл f, отбрасывая все элементы с позиции файлового указателя.

function FileSize(f: file): LongInt; Возвращает количество байт в нетипизированном файле f.

function FilePos(f: file): LongInt; Возвращает текущую позицию файлового указателя в нетипизированном файле f.

procedure Seek(f: file; n: LongInt); Устанавливает текущую позицию файлового указателя в нетипизированном файле f на байт с номером n.

Небольшое отступление. Всё то, что было написано выше во всех параграфах справедливо к языку Pascal  в целом, т.е. эти знания вы можете применять как в среде разработки PascalABC.NET, так и в TurboPascal. То что было сказано выше про нетипизированные файлы справедливо только в среде программирования PascalABC.NET.

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

Напомню, среда программирования PascalABC.NET была создана для обучения принципам программирования. Она ориентирована на программирование под операционную систему Windows. Поэтому PascalABC.NET отличается от «изначального» TurboPascal. В данном учебнике за основу был выбран язык PascalABC.NET, поэтому раскрывать принципы работы с нетипизированными файлами, которые заложены в TurboPascal в рамках данного учебника я не буду.

Думаю, если вы обучаетесь в TurboPascal, то наверняка вы читаете параллельно и другую соответствующую литературу. Следовательно, в ней вы и узнаете про то, как реализована работа  с нетипизированными файлами в TurboPascal.


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

Сделать это можно следующим образом: запишем переменную типа String в нетипизированный файл, затем откроем этот файл как типизированный и выведем его на экран в виде последовательности байтов. Потом проанализируем эту последовательность.

Далее код программы реализующей вышесказанное:


var fnet:file;

    fbyte:file of byte;

    s:string;

    b:byte;

   

begin

  s:='АБВГД';

  Assign(fnet,'c:\Exp.str');

  Rewrite(fnet);

  write(fnet,s);

  Close(fnet);

  Assign(fbyte,'c:\Exp.str');

  Reset(fbyte);

  while not Eof(fbyte) do

    begin

      read(fbyte,b);

      write(b,'  ');

    end

  Close(fbyte);

end.

_________________________________

5  192  193  194  195  196 


Проанализировав результат работы программы, можно придти к следующим умозаключениям: данная переменная занимает всего 6 байт памяти. Первый байт содержит количество символов в строке, последующие байты являются символами. Для проверки такого утверждения допишем в программу следующий код:


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

  writeln;

  Reset(fbyte);

  read(fbyte,b);

  write(b,'  ');

  while not Eof(fbyte) do

    begin

      read(fbyte,b);

      write(Chr(b):3,'  ');

    end

  Close(fbyte);

end.

_____________________________

5  192  193  194  195  196 

5    А    Б    В    Г    Д 


Как видно из результата, наши рассуждения были верны. Получается, что в PascalABC.NET переменная типа String в памяти храниться следующим образом: первый байт содержит количество символов в строке, последующие байты содержат символы строки.

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

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


Подпрограммы для работы с файлами.

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

procedure Erase(f: FileType);

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


var f:file of Byte;

begin

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

  erase(f);

end.


Функции для работы с именами файлов:

procedure Rename(f: FileType; newname: string); переименовывает файл, связанный с файловой переменной f, давая ему новое имя, находящееся в строке newname. При использовании данной процедуры так же переименовываемый файл не должен быть открыт, или использоваться другой программой:


var f:file of Byte;

begin

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

  rename(f,'c:\124.int');

end.


function ExtractFileName(fname: string): string; выделяет имя файла из полного имени файла fname.

function ExtractFileExt(fname: string): string; выделяет расширение из полного имени файла fname.

function ExtractFilePath(fname: string): string; выделяет путь из полного имени файла fname.

function ExtractFileDir(fname: string): string; выделяет имя диска и путь из полного имени файла fname.

Пример программы с данными функциями:


var s:string;

begin

  s:='c:\Papka_1\Papka_2\file.dat';

  writeln('Полное имя файла - ',s);

  writeln('ExtractFileName(s) - ',ExtractFileName(s));

  writeln('ExtractFileExt(s) - ',ExtractFileExt(s));

  writeln('ExtractFilePath(s) - ',ExtractFilePath(s));

  writeln('ExtractFileDir(s) - ',ExtractFileDir(s));

end.

_______________________________________________________

Полное имя файла - c:\Papka_1\Papka_2\file.dat

ExtractFileName(s) - file.dat

ExtractFileExt(s) - .dat

ExtractFilePath(s) - c:\Papka_1\Papka_2\

ExtractFileDir(s) - c:\Papka_1\Papka_2



Процедуры и функции для работы с файлами, каталогами и дисками.

function GetDir: string;  возвращает текущий каталог.

procedure ChDir(s: string); меняет текущий каталог.

function SetCurrentDir(s: string): boolean; Устанавливает текущий каталог. Возвращает True, если каталог успешно установлен.

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

Кстати с помощью функции GetDir можете узнать, где находится ваша программа:



begin

  writeln('Эта программа находится в ',GetDir);

  writeln('Теперь сменим текущий каталог на C:\Program Files');

  ChDir('C:\Program Files');

  writeln('Уточняем, какой текущий каталог на данный момент - ',GetDir);

end.

________________________________________________________________________

Эта программа находится в C:\PABCWork.NET

Теперь сменим текущий каталог на C:\Program Files

Уточняем, какой текущий каталог на данный момент - C:\Program Files


function ChangeFileNameExtension(name,newext: string): string; Изменяет расширение файла с именем name на newext. Другими словами, функция возвращает имя файла name с изменённым расширением на newext. Пример:


var s:string;

begin

  s:=ChangeFileNameExtension('c:\Exp.str','dat');

  writeln(s);

end.

___________________________________________________

c:\Exp.dat


Следующие подпрограммы будут приведены без примеров. Думаю, вы без труда сможете с ними разобраться. Примеры их использования будет предложено создать самостоятельно в задачах для самостоятельного решения.

procedure MkDir(s: string);  создает каталог.

function CreateDir(s: string): boolean; создает каталог. Возвращает True, если каталог успешно создан.

procedure RmDir(s: string); удаляет каталог.

function RemoveDir(s: string): boolean; Удаляет каталог. Возвращает True, если каталог успешно удален.

function DeleteFile(s: string): boolean; удаляет файл. Если файл не может быть удален, то возвращает False.

function FileExists(name: string): boolean; Возвращает True, если файл с именем name существует. Прежде чем открывать какой-либо файл, с помощью данной функции можно убедиться

function DiskFree(diskname: string):LongInt; Возвращает свободное место в байтах на диске с именем diskname.

function DiskSize(diskname: string):LongInt; Возвращает размер в байтах на диске с именем diskname.

function DiskFree(disk: integer):LongInt; Возвращает свободное место в байтах на диске disk.

function DiskSize(disk: integer):LongInt; Возвращает размер в байтах на диске disk.

В обоих последних функциях: disk=0 текущий диск, disk=1 диск A, disk=2 диск B, и т.д.


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


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


Задачи.

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

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


Решение.

1.

Program StrukturaString;

//Программа демонстрирует структуру переменных типа String


Var f:file;

    i,k:byte;

    sTemp:string;

    cTemp:char;

begin

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

  rewrite(f);

//Формируем нетипизированный файл случайными строками 

  For i:=1 to random(20) do

   begin

     sTemp:='';

   //Формируем строку 

     for k:=1 to random(20) do sTemp:=sTemp+chr(random(32,255));

     Write(f,sTemp);

   end;

  close(f);

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

  Writeln('Количество символов  Содиржимое строки');

  reset(f);

  while not eof(f) do

    begin

      read(f,i);

    //Выводим количесвто символов 

      write(i:19,'  ');

    //Выводим содержимое строки

      for k:=1 to i do

       begin

        read(f,cTemp);

        write(cTemp);

       end;

      writeln;

    end;

  close(f); 

end.

_______________________________________________________________________

Количество символов  Содиржимое строки

                 16  Я$‹*ъ®†њћMсдШ.Ж2

                 11  юЖ‚x*Jv‰єжљ

                 15  (щ<л}7ЭѓOњu>©Yх

                 18  †;vbЄљMLд~ФЪ4Ў_ИмУ

                 10  SФш{чи®n‚q

                  6  ПСTѓ"џ


2. Данную задачу решите самостоятельно.


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