Материал и презентация:Сазонов Д.О. ПМиЭММ e-mail:nimnul@yandex.ru Файлом можно назвать любые данные, записанные на внешний носитель, объединенные одним именем Как OS представляет файл? В начале диска создается так называемая ТАБЛИЦА ext2 ntfs РАЗМЕЩЕНИЯ ФАЙЛОВ (File Allocation Table), в программировании просто называемая FAT. В fat32 cdfsинформация о данной таблице как раз содержится файлах. Если быть точнее, то имя файла, vfat его длинна, его атрибуты и номер по которому файл размещен на диске. Собственно говоря вы можете для примера загрузить программу DE (Disk Editor) из комплекта Norton Utilites. То, что вы там увидите и будет FAT. Например: Имя Рас Размер Дата Время Кластер Арх Т/Ч Сис Скр Кат Том IO DOS 40774 5-31-94 6:22 am 2 Т/Ч Сис Скр MSDOS DOS 38138 5-31-94 6:22 am 4 Т/Ч Сис Скр NIMNUL 0 7-05-98 6:46 pm 0 Арх Том хCANDISK LOG 732 7-31-96 1:58 pm 14 Арх AT.e.m.p ... 4294967295 15-31-07 7:63 pm 0 Т/Ч Сис Скр Том TEMP 0 7-05-98 7:11 pm 3599 Кат CONFIG SYS 124 7-29-96 8:38 pm 765 Арх AU.s.e.r .s. 4294967295 15-31-07 7:63 pm 0 Т/Ч Сис Скр Том USERS 0 7-05-98 7:16 pm 178 Кат QUIZ 0 7-28-96 4:53 pm 1091 Кат BOOTLOG PRV 24259 7-07-98 3:28 pm 11 Арх Скр LINUX 0 7-30-96 7:35 am 13 Кат Ag.a.m.e .s. 4294967295 15-31-07 7:63 pm 0 Т/Ч Сис Скр Том GAMES 0 7-05-98 9:05 pm 5676 Кат AUTOEXEC BAT 994 7-29-96 8:38 pm 799 Арх Т/Ч MSDOS SYS 1641 7-08-98 2:04 pm 811 Арх Т/Ч Сис Скр BOOTLOG TXT 24006 7-07-98 4:27 pm 9 Арх Скр SUHDLOG DAT 11821 7-07-98 3:17 pm 10669 Т/Ч Скр Когда пользователь хочет что либо сделать с файлом и дает об этом знать машине, компьютер сначала ищет имя этого файла в FAT, затем по имени определяет где этот файл начинается и сколько занимает - его начало и длину, ну а дальше все просто - загружается файл и с ним выполняются какие-либо действия из выше перечисленных. Теперь вы догадались, почему в одном каталоге не может быть два файла с одинаковыми именами? Собственно говоря, даже если такое и произойдет (в результате вмешательства опытного пользователя), то работать можно будет только с тем файлом, который находится первым по списку. Логический и физический файл. Для удобства разделим файлы на две группы. Первая группа - это физический файл. Файл который реально находится на диске, и вообще любой файл. Логическим же файлом назовем файл с которым будем работать в программе, но как только мы выйдем из среды программирования или же перестанем работать с этим файлом он станет физическим. Зачем нужно такое разделение? Дело в том, что все фалы на диске всегда представляют собой однотипную последовательность данный, где каждому элементу этих данных соответствует только одна ячейка. (вспомните массивы). Получается, что каждый файл это массив var test_file:array[1..n] of char; Но, что делать, если нам нужно поместить в файл число типа integer или real, или какой-нибудь другой тип. Для этого в программе указывают тип данных которые, якобы будут записываться в файл, например integer (целый тип). Далее записывают элементы- если подумать логически, то раз в файл записываются элементы типа integer, то и сам файл тоже будет иметь этот тип. Но на самом деле это не так. Так как на каждое число в файле выделена одна ячейка, никак нельзя записать две. По этому каждое число разбивается на несколько частей. Этой разбивкой занимается компилятор и нам не надо об этом заботится, достаточно записать в файл любого типа, а компилятор сам преобразует его. Продемонстрировать это можно так (грубый пример). Допустим дан файл: В каждой ячейке может поместиться только один символ. Это есть физический файл. Логический файл мы создаем, когда присваиваем файловой переменной тип файла. В Pascal: a: file of integer; Теперь мы записываем в него число, например 42 и число 76. Если бы это был массив, было бы: 42 76 Задача же компилятора состоит в том, чтобы преобразовать число из двух символов в два числа по одному символу в каждом. По этому файл будет выглядеть так: 2 4 6 7 Если приглядеться, то можно увидеть, что при записи в файл двух символов, компилятор меняет из местами. Представление файлов в PASCAL Как и в других языках высокого уровня в языке PASCAL заложена работа с файлами. Надо отметить, что во всех языках программирования работа с файлами представляет собой примерно одно и то же, различаясь только разными подходами и разными командами. По своей же сути файлы обрабатываются одинаково во всех языках. На данном моменте нашей задачей будет являться рассмотреть, посредством чего PASCAL взаимодействует с файлами и файлом в целом. Поскольку PASCAL структурный язык прежде всего нам придется узнать как описывается файл и что представляет собой этот тип данных. Прежде всего начнем с того, что PASCAL может работать с тремя видами логических файлов: текстовые файлы, типизированные файлы, и файлы без типа. Соответственно в текстовых файлах записывается и считывается текстовые строки (например можно записать туда какое-нибудь послание). Типизированные файлы предназначены для записи в них определенного типа данных (поскольку язык PASCAL сам по себе типизированный - у каждой переменной должен быть свой тип, обойтись без типизированных файлов обойтись было бы крайне тяжело). Файл без типа представляет собой - физический файл на диске Представление файлов в PASCAL Файл представляется как номер, которое обязательно должно храниться в переменной. Соответственно у каждого файла должна быть своя переменная. Переменные связанные таким образом с файлами называются файловыми переменными. Описание файлов Поскольку в PASCAL все переменные должны быть описаны в заголовке, соответственно файловые переменные должны быть описаны там же. Например: VAR f: file; T: text; Fi,Fi1,Fi2: file of integer; Fr: file of real; Fw,Fw2: file of word; Fb: file of byte; Чтобы не запутаться при составлении большой программы рекомендую вам обозначать файловые переменные с буквы f (или с Т - если файл текстовый).На практике в учебном же процессе Вам скорей всего не придется работать с файлами без типа. Если файл без типа то переменные будут f1,f2,f3,…… Если файл типизированный, то разумно после буквы f указывать первую букву типа файла, как это делалось в примере выше. Связь файловой переменной с физическим файлом После того как мы описали файловую переменную, мы прошли только 1/3 пути т.к. описанием мы только сказали компилятору, что у нас будет какой-то файл и за него будет "отвечать" конкретная переменная. (дали переменной тип). Следующим шагом будет связь переменной с конкретным файлом, находящимся на дискете или винчестере. После этого файловая переменная примет номер файла. И далее, чтобы обратиться к файлу (записать или считать из него), нам будет достаточно обратиться к файловой переменной отвечающей за этот файл. И наконец, когда компилятор знает какая переменная с каким файлом связана, нам надо сказать, что мы будем делать с файлом. (записывать, считывать из него и т.д.). На практике это будет выглядеть так: Var f: file of integer; ….. Begin …… Assign(f,'имя файла'); Reset(f); …. End. Давайте теперь рассмотрим подробнее, что есть что. Вы уже наверное догадались, что связь с физическим файлом выполняется посредством оператора ASSIGN. Кроме этого у ASSIGN есть два обязательных параметра: первый - это переменная с которой связывается файл, а второй - это взятое в кавычки имя файла с которым будет происходить работа. Причем имя файла может также содержать путь к файлу. Например: Assign(f,'f2.txt'); После того, как мы связали переменную и файл, надо сказать компилятору что мы будем Теперь вы знаете как открыть файл написать и начать делать с файлом, длякогда этого сразу после оператора Assign следует один из следующихработу операторов: с ним нелишне будет сказать, что ВСЕГДА после работы с файлом его обязательно надо RESET(имя файловой переменной) закрыть. Особенно это относится к случаю когда REWRITE(имя файловой переменной) APPEND(имя файловой переменной) что-нибудь записывается в файл. Оператор который это делает называется CLOSE и в качестве RESET - говорит о том, что мы связали переменную с файлом для того, чтобы что либо записать параметра ему надооткрыть передать имя файловой или прочитать из него. Иными словами для чтения/записи (используется чаще всего). REWRITE - говорит о том, что файл надо создать заново на диске т.е. если такого файла не было то переменной. Например: CLOSE(f); он создается, если был то стирается. APPEND - сообщает компилятору, что все последующие записи в файл будет добавлены к его концу таким образом файл будет расти, но при этом в него можно только записывать. Запись и чтение из файла Изначально файлы были придуманы для хранения, добавления, стирания и обработки различной информации по этому самым важным моментом при работе с файлами является запись информации в файл и чтение из него. Для чтения и записи существует несколько процедур и функций в PASCAL, но пока нас будут интересовать только две, которые Вам уже давно известны. Это READ и WRITE. Соответственно READ читает информацию из файла, а WRITE - записывает в него. Формат этих команд следующий: READ (имя файловой переменной, переменная в которую будет производиться чтение) WRITE(имя файловой переменной, переменная значение которой запишется в файл) Естественно, что пользоваться READ и WRITE можно только после того, как файловая переменная связана с конкретным файлом с помощью ASSIGN. из файла Примеры: Чтение запись в файл VAR fi: file of integer; VAR fi: file of integer; Чтение с помощью цикла I:integer; I:integer; Тоже самое Begin можно Begin сделать с помощью цикла VAR fi: file of integer; Assign(fi,'test.tmp'); Assign(fi,'test.tmp'); I,j:integer; VAR fi: file Reset(fi); of integer; Reset(fi); Begin Read(fi,i); I:integer; I:=3; Assign(fi,'test.tmp'); Write(i); {Вывод содержимого файла на экран} Begin Write(fi,i); Reset(fi); Read(fi,i); Assign(fi,'test.tmp'); I:=2; For i:=1 to 3 do begin Reset(fi); Write(i); Write(fi,i); Read(fi,j); Read(fi,i); For i:=3 downto I:=1;1 do Writeln(j); Write(fi,i); Write(i); Write(fi,i); End; принципе при чтении файла CLOSE Close(fi); {в Close(fi); можно не использовать} Close(fi); End. End; End. Close(fi); End; Почему READ и WRITE? А действительно почему мы пользуемся одними и теми же операторами для печати на экран и вывода в файл, для чтения символа с клавиатуры и чтения из файла? По сути дела получается что существует два READ и два WRITE. Первые из которых имеют всего один параметр, а вторым требуется два. С точки зрения языка PASCAL такое недопустимая ошибка - нельзя чтобы были две одинаковых процедуры с разным или даже одинаковым количеством параметров. Так в чем же тогда дело? Оказывается компилятор Паскаля считает клавиатуру и экран дисплея тоже файлами. Причем у этих "файлов" даже есть имена: клавиатура называется input, а экран монитора output. Далее приведем две совершенно различные конструкции которые на самом деле являются одним и тем же. Var f:file; Begin Assign(f,'ountput'); Reset(f); Write(f,'Hello world!'); Close(f); End. Вся эта программа может быть заменена всего одним оператором: Write('Hello world!'); Точно также работает и read. Вывод: по умолчанию для вывода используется конструкция Write(output,<текст или переменная на вывод>), а для ввода Read(input,<переменная для ввода данных>), где output и input файлы. В начале программы как и всем файлам в PASCAL output и input должно присваиваться имя физического файла, но так как монитор и клавиатура не является физическим файлом на диске им не присваивается ничего т.е. выполняется следующие команды: Для вывода Assign(output,''); Rewrite(output); Для ввода данных Assign(input,''); Rewrite(input); Тем не менее мы можем связать клавиатуру и экран монитора с физическим файлом на диске. Такая связь называется в программировании перенаправлением ввода. Для этого нам надо указать имя файла в операторе Assign. В этом случае вывод будет происходит в файл, а вывод из файла. Текстовые файлы С типом файла TEXT: C перенаправлением ввода: Какuses было файлы хранят в себе crt; сказано выше текстовые uses crt; var t:text; данные имеющие тип beginstring или char. различные begin clrscr; файлы такого типа Даже в разделе описания переменных clrscr; {вывод на экран монитора} описываются иначе остальных: вместо file пишется text. {вывод на экран монитора} write('один'); Например: write('один'); writeln(' два'); Varwriteln(' t,t1: text; два'); writeln('три'); writeln('три'); {переопределяем вывод на вывод в файл} {Вывод впримером текстовый файл} assign(output,'screen.tmp'); Хорошим текстового файла может являться монитор. assign(t,'text.tmp'); rewrite(output); В текстовом файле как и на экране монитора все будет rewrite(t); write('один'); записываться так как оно выглядит на два'); экране. Иными словами write(t,'один'); writeln(' это простое перенаправление ввода с монитора в файл. Две writeln(t,' два'); writeln('три'); writeln(t,'три'); close(output); следующие программы аналогичны. close(t); end. end. Ввод же из файла осуществляется точно так же как и ввод и с клавиатуры, за исключением того, что Вам не придется нажимать на клавиши все правила ввода с клавиатуры справедливы и ввода с файла. Правда, это только для текстовых файлов. Приведем пример ввода: Но для начала надо создать текстовый файл. Для этого воспользуемся одной из приведенных выше программ. В профессиональной практике при работе с текстовыми файлами предпочтительнее использовать вторую программу с перенаправлением ввода, поскольку она не требует описания файловой переменной, а работа с самим файлом выглядит привычнее. uses crt; begin clrscr; {переопределяем вывод на вывод в файл} assign(output,'prim.tmp'); rewrite(output); writeln('10 12 21 56 42'); write('15'); close(output); end. Мы записываем в файл prim.tmp числа 10 12 21 56 42 и на следующей строке число 15. Если бы мы все это вводили с клавиатуры (через READ), то проделали бы следующие действия. 10 пробел 12 пробел 21 пробел 56 пробел 42 ENTER 15 ENTER. Теперь, при считывании текстового файла за нас это проделает компьютер. Не забывайте, что чтение текстового файла - это лишь перенаправление ввода клавиатуры. uses crt; var a:integer; begin clrscr; assign(input,'prim.tmp'); {Перенаправляем ввод из файла на клавиатуру } reset(input); Как вы уже, наверно, заметили в текстовых файлах можно хранить и числа, причем отделяются числа друг от друга пробелом. read(a); {Считали первое число} write(a,' '); {вывели на экраних число и пробел, чтобы числа не сливались И читать можно с помощью read,друг ас другом.} чтобы перейти к следующей строчке read(a); write(a,' '); необходимо использовать readln. Тоже read(a); write(a,' '); самое относится и к выводу текстовых read(a); write(a,' '); файлов. readln(a); {перешли на строчку ниже. (в фале)} writeln(a,' '); {Отступили строчку на экране монитора и вывели число} read(a); write(a,' '); end. Пример 1.Записать в текстовый файл одномерный Пример массив из 10 элементов и вывести содержимое текстового 2. Записать в текстовый файл одномерный массив файла. из 10 элементов и вывести содержимое текстового файла. При этом не использовать uses crt; перенаправление вывода. Решить задачу с помощью файловой переменной. var a:array[1..10] of integer; i,k:integer; uses crt; var a:array[1..10] of integer; begin i,k:integer; clrscr; t:text; {заполняем массив произвольными числами} for i:=1 to high(a) do begin begin a[i]:=random(100); clrscr; write(a[i],' '); {заполняем массив произвольными числами} end; for i:=1 to high(a) do begin {перенаправляем ввод} a[i]:=random(100); assign(output,'prim.tmp'); write(a[i],' '); rewrite(output); end; {вывод массива в файл который связан с экраном монитора} {присваиваем файловой переменной физическое имя файла} for i:=1 to high(a) do write(a[i],' '); assign(t,'prim.tmp'); close(output); rewrite(t); {вывод массива в файл} {теперь прочитаем содержимое файла} for i:=1 to high(a) do begin {А чтобы вывод содержимого был на экран, а write(t,a[i]); не в файл надо опять перенаправить вывод, но {для отделения чисел друг от друга} на сей раз на экран} write(t,' '); end; assign(output,''); close(t); rewrite(output); {теперь прочитаем содержимое файла} assign(t,'prim.tmp'); assign(input,'prim.tmp'); reset(t); reset(input); writeln; writeln; writeln('Содержимое файла:'); writeln('Содержимое файла:'); for i:=1 to high(a) do begin for i:=1 to high(a) do begin read(t,k); read(k); write(k,' '); write(k,' '); end; end; readln; readln; end. end. Стандартные процедуры и функции для работы с файлами FilePos(файловая переменная) - возвращает текущую позицию в файле. Пример: .... Writeln(FilePos(fi)); FileSize(файловая переменная) - возвращает общую длину файла в байтах Пример: .... Writeln(FileSize(fi)); Truncate(файловая переменная) - удаляет все от текущей позиции в файле и до конца файла. Seek(файловая переменная, позиция) - устанавливает позицию указателя в файле. Дополнительные процедуры и функции для работы с файлами Для того, чтобы использовать дополнительные возможности работы с файлами необходимо подключить дополнительный модуль под названием WinDos в раздел USES начала программы. Например: Uses crt, windos; Данный модуль дает возможность работать с функциями и процедурами операционной системой MS DOS. Exec(имя программы,''); - выполняет заданную программу при учете, что хватит памяти для выполнения. Например: Exec('j:\d\lang\tp7\test.com',''); Exec('test.exe', ''); DosVersion - возвращает текущую версию MS DOS. Пример: Writeln(DosVersion); DiskFree(номер дискового устройства) - возвращает количество свободного места на диске. Номер устройству определяется по правилу: 0 - текущее устройство (которое работает в данный момент) 1 - Дисковод 3,5`` 2 - Второй дисковод 3.5`` (если он есть) 3 - Винчестер - диск С. 4 - Диск D и и.д. Функция возвращает (- 1) - если устройства не существует. Например: Write('Введите номер устройства:'); Readln(N); If DiskFree(N)=-1 then writeln('Устройства не существует') else Writeln('Свободно:', DiskFree(N)); Успехов Вам!