Программирование работы с файлами на дисках

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

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

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

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

С каждой конкретной записью данных, размещаемой в файле, связывают два понятия: логическая запись и физическая запись. Под логической записью понимают порцию информации, измеренную в байтах, которая определена списком вывода данных, записанным в том или ином операторе вывода. Например, в операторах Write ('Готовность №Г); Writeln ('xl=', х 1, 'х2=, х2, 'хЗ=', хЗ); Write (а:6:2, Ь:6:2, с:6:2); списки вывода различны, и они образуют последовательности байт различной длины, но по определению они представляют собой логические записи.

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

По способу кодирования информации, выводимой в записях файла, последние делятся на текстовые, типизированные и бес-типовые. В текстовых файлах данные на диске представляются последовательностями двоичных кодов символов или, упрощенно говоря, в символьном виде. Они распределяются по строкам, каждая из которых заканчивается символом «конец строки». Конец файла обозначается специальным символом «конец файла». Текстовый файл всегда можно прочитать с помощью редактора текстов Edit, имеющегося в системе программирования Turbo Pascal 7.0.

Типизированные файлы состоят из записей, хранящих данные одного типа, чаще числового. Они представлены в двоичных кодах чисел, говорят в бинарном виде и занимают меньше места на диске, чем текстовые файлы. Такие файлы заканчиваются символом «конец файла» и не читаются редактором Edit.

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

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

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

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

Программирование работы с файлами любого типа на дисках предусматривает выполнение следующих инструкций.

При записи в файл.

  • 1. Объявить файловую переменную.
  • 2. Назначить этой переменной файл.
  • 3. Открыть файл для записи.
  • 4. Записать данные в файл.
  • 5. Закрыть файл.

При чтении из файла.

  • 1. Объявить файловую переменную.
  • 2. Назначить этой переменной файл.
  • 3. Открыть файл для чтения.
  • 4. Записать в ОП данные из файла.
  • 5. Закрыть файл.

Рассмотрим смысл этих инструкций и то, как они программируются.

Идеология языка Turbo Pascal 7.0 подразумевает объявление всех переменных, используемых в программе. Раньше мы объявляли обычные переменные, массивы, строки, записи, множества. При этом обязательно указывался тип данных, образующих перечисленные структуры. Эти директивы прежде всего нужны были компилятору для выделения памяти под данные. Поскольку файл — это тоже структура данных, при обмене с ОП требующая где-то размещения ее элементов, она также должна быть объявлена. Это делается с помощью ввода в рассмотрение файловой переменной.

Файловые переменные всех типов файлов объявляются в разделе объявления переменных, т. е. после аббревиатуры Var.

Для типизированных файлов файловая переменная объявляется так:

Var

Имя переменной: file of Тип элементов записей;

Например,

Var

f: file of integer;

Var

Alfa: file of real;

Var

Beta: file of word;

По смыслу эти объявления означают, что f, Alfa, Beta — это переменные, идентифицирующие некоторые файлы, состоящие из записей чисел соответственно целого, вещественного и word

типов.

Предварительно можно ввести свой тип данных, например

так:

Туре

Focus=Array 11..100] of real; а затем определить файловую переменную

Var

В: file of Focus; которая идентифицирует файл. Записью этого файла является одномерный массив из 100 вещественных чисел.

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

Var

f: text; rez: text;

Бестиповый файл описывается с помощью служебного слова

file:

Var

Имя переменной: file;

Например:

Var

tt: file; — означает файл, tt — бестиповый.

По объявлению файловой переменной в процессе компиляции программы компилятор выделяет буфер для обмена данными ОП с тем или иным диском ПК.

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

Для назначения файла переменной применяется процедура Assign (Имя переменной, Имя файла). В переводе с англ, слово Assign означает назначить. Например,

Var

Alfa: file of real;

Begin

Assign (Alfa, 'C: pmat.dat');

Текстовая константа 'C: pmat.dat' определяет диск С, на котором расположен файл mat.dat в подкаталоге tp. При всех назначениях рекомендуется всегда указывать диск, где находится файл, и путь к нему.

Возможно предварительное определение имени файла, например matrix='C: pmat.dat', с последующим назначением

Assign (Alfa, matrix).

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

Открытие файла для записи (чтения) означает, что соответствующий сектор диска, с которого начинаются записи, становится доступным для вывода-ввода информации.

Для открытия файла для записи предназначена процедура Rewrite (имя файловой переменной). Например, Rewrite (Alfa) — открыть файл для записи, связанной с переменной Alfa. При этом процедура Rewrite (f), где f — имя файловой переменной, не только разрешает доступ к дорожкам диска, занимаемым файлом, но и уничтожает ту информацию, которая хранилась на них прежде.

Открытие файла для чтения осуществляется процедурой Reset (Имя файловой переменной). Например, Reset (Beta) — открыть файл, определяемый переменной Beta, для чтения.

Передача данных на диск из ОП осуществляется процедурой Write (Имя файловой переменной, список вывода), например Write (F,x), Write (Alfa, x,y,z), Write (Rez, 'Спасибо за внимание') и т. д. В перечисленных процедурах вывода передаваемыми на диск записями являются соответственно х; х, у, z, Спасибо за внимание. В первом случае — это значение одной переменной х, во втором — значения трех переменных х, у, z, в третьем случае передаваемая запись представляет собой строковую константу.

Для чтения данных с диска предназначена процедура Read (Имя файловой переменной, Список ввода), например Read (Beta, х), Read (Top, х,, х2,...,х„), Read (’Вектор X размера п=20'). В этом примере записями, читаемыми с диска, являются соответственно значение переменной х, значения констант вектора х,, х2, ..., хп и текст «Вектор X размера п=20».

В текстовых файлах, кроме указанных процедур ввода-вывода, могут использоваться процедуры Writeln (Имя файловой переменной, Список вывода), Readln (Имя переменной, Список ввода). Особенность процедуры Writeln состоит в том, что она отмечает конец каждой записываемой строки кодом ASCII. Процедура Readln считывает текущую строку файла и переводит курсор на новую строку не по признаку конца строки, а по имеющимся значениям данных в строке. Дальнейшее чтение происходит с новой строки.

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

Процедура Close (Имя файловой переменной) закрывает файл, который был открыт процедурой Rewrite или Reset. Эта процедура записывается в конце фрагмента программы, в котором запрограммированы действия с файлом. При записи в файл она обязательна, так как только в этом случае вся информация передается с буфера на диск. Приведем примеры.

Пусть в файл p.dat, расположенный на диске Е в каталоге temp, необходимо записать вектор X размера 6 с известными значениями компонент х,, х2, ..., х„, а затем прочитать его с диска. Последовательность инструкций будет такой:

Туре

Massiv=Array [1..6] of real; {Объявление массива}

Var

Vek: file of Massiv; {Объявление файловой переменной}

Begin

Assign (Vek, 'E: empp.dat'); {Назначение файла}

Rewrite (Vek); {Открытие файла для записи}

Write (Vek, X|, X2, хз, X4, Х5, xg); {Запись в файл}

Close (Vek); {Закрытие файла}

Reset (Vek); {Открытие файла для чтения}

Read (Vek, xj, Х2, хз, Х4, X5, хД; {Чтение файла}

Close (Vek); {Закрытие файла}

End.

В текстовых файлах, кроме процедуры открытия файла для записи Rewrite (f), где f — имя файловой переменной, используется процедура Append (f) — дозаписи информации в файл. Она применяется к файлам, содержащим некоторую информацию. Если, например, файл a.dat, расположенный на диске С, содержит некоторую информацию о студентах, то пополнить его очередными данными можно следующим образом:

Var

Rez: text;

Begin

Assign (Rez, 'C:a.dat');

Append (Rez);

Writeln (Rez, 'Петров Игорь Алексеевич');

Close (Rez);

End.

В языке со всеми видами файлов предусмотрена возможность использования процедур переименования файлов и их уничтожения: Rename (f, Новое имя файла), Erase (f), где f — имя файловой переменной. Эти процедуры применяются к закрытым файлам. Кроме того, в программах обработки файлов широко используются функции Eof (f) и IOResult.

Функция Eof (f) (End of file) — конец файла — принимает два значения: истина—ложь. Когда при чтении-записи достигнут конец файла, он принимает значение истина, во всех других случаях — значение ложь.

Функция IOResult — результат ввода-вывода — чаще всего используется для контроля открытия файла. Если открытие файла произошло успешно, она принимает значение 0. Использование этой функции в работе возможно только по директиве компилятору. Директива {$1-} записывается перед процедурой открытия файла, директива {$1+} — после этой процедуры. В стандартном режиме компиляции действует директива {$1+}.

Рассмотрим пример использования функций Eof (f) и IOResult.

Пусть в подразделении бухгалтерии некоторого предприятия на диске Е имеется файл ds.dat, содержащий доходы по разным операциям. Требуется найти суммарный доход и записать его в другой файл s.dat на диск Е. Программа может иметь такой вид.

Program Dohod; {Вычисление дохода по операциям}

Var

fi: text; {Объявление файловой переменной исходного}

{файла ds.dat}

fr: text; {Объявление файловой переменной результирующего} {файла}

dh: real; {Доход по операции — запись в файле}

S: real; {Суммарный доход по всем операциям}

Begin

Assign (fi, 'E:ds.dat'); {Назначение файла переменной fi}

{$!-} {Директива компилятору}

Reset (Г1);{Открыть файл fi}

{$!+} {Директива компилятору}

Tf IOResult=0 Then

Begin

S:=0;

While Not Eof (fi) {Если не конец файла, то читать из него}

Begin

Readln (fi, dh); {Чтение из файла}

S:=S+dh; {Суммирование доходов}

End;

Close (fi); {Закрыть файл}

Assign (fr, 'E:s.dat'); {Назначение файла переменной fr} Rewrite (fr); {Открыть файл для записи}

Writeln (fr, 'Сумм, доход S=', S: 10:2); {Запись в файл} Close (fr);

End;

Else

Writeln ('Файл не может быть открыт');

End.

В этой программе по директиве {$1-} включается в работу функция IOResult, и если ее значение равно нулю, осуществляется чтение записей из файла ds.dat и их суммирование. Далее найденная сумма записывается в файл s.dat. В противном случае на экран выводится сообщение о том, что файл не может быть открыт.

Операционная система компьютера взаимодействует с клавиатурой, дисплеем, принтером, портами ввода-вывода как с файлами, имеющими свои имена и адреса. Например, для клавиатуры используется имя Con (Консоль), для принтера Ргп, для параллельных портов Lpt 1—Lpt3 и т. д. Это дает возможность файлам, находящимся на этих устройствах, назначать переменные и использовать эти имена в программах. В качестве примера рассмотрим программу построчного вывода матрицы А на принтер.

Program MatrixA; {Вывод матрицы на принтер}

Var

fa: text; {Объявление файловой переменной}

A: Array fl..50,1..30] of real; {Объявление массива}

i,j,m,n: byte; {Индексы строк, столбцов А, к-во строк и столбцов}

Begin

Assign (fa, 'Prn'); {Назначение вывода на принтер}

Rewrite (fa); {Открыть файл}

Writeln (fa, 'Матрица А); {Вывод в файл заголовка}

Write ('Введите m,n'); Readln (n,m);

For i=l to m do {Цикл по строкам A}

Begin

Forj=l to n do {Цикл по столбцам A}

Write (fa, A[i,j]:6:2 ' '); {Запись строки A}

Writeln (fa); {Переход к началу очередной строки}

End;

Close (fa); {Закрыть файл}

End.

Раньше мы говорили о том, что при создании файлов прямого доступа их записи нумеруются. Первая запись получает номер 0, вторая 1 и т. д. до п - 1 записи, где п — общее число записей в файле. Для удобной работы с нумерованными записями файлов в языке Turbo Pascal 7.0 предусмотрен ряд стандартных процедур и функций.

Поиск /-й записи, і < п - 1, осуществляется процедурой Seek(f,i), где f — файловая переменная, а /' — целое число типа Longint. Эта процедура устанавливает указатель записи на /'-ю запись, после этого она может быть прочитана или на ее место помещена другая запись такого же формата.

Функция Filesize (0 определяет число записей в файле. При этом файл должен быть открыт.

Функция Filepos (f) определяет текущую позицию указателя файла, т. е. указывает текущий номер записи.

Процедура Trancat (f) отсекает «хвост» файла, начиная с текущей записи.

Как используются эти процедуры и функции, покажем на следующем примере.

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

Program Fa; {Обращения записей файла}

Var

A: Array fl..100] of real; {Объявление массива}

a,b: real; {Границы интервала генерации чисел, а<Ь}

n: Word; {Размер массива}

i: Word; {Индекс элемента массива}

f: file of real; {Файловая переменная}

m: Word; {Число элементов половины массива}

Begin

Writeln ('Введите n,a,b'); Readln (n,a,b);

Name='C:m.dat' {Имя файла и его размещение}

Assign (f, Name); {Назначение переменной f файла}

Rewrite (f); {Открытие файла}

m:=n div 2; {Определение числа элементов половины массива} Randomize; {Инициация датчика случайных чисел}

For i= 1 to т do Begin

A[i]:=Int(a+Random*(b-a)); {Выработка i-ro числа}

Write (f, A[i]); {Запись числа в файл}

End;

Writeln ('К-во записей файла =', File size (f));

Close (f); {Закрытие файла}

Reset (f); {Открытие файла для чтения}

For i=0 to m-1 do

Begin

Seek(f,i); {Установка указателя на i-ю запись}

Read (f,a); {Чтение записи в переменную а} Seek(f,(n-l)-i); {Установка указателя на (n-l)-i-io}

{запись}

Read (f,b); {Чтение записи в переменную Ь}

Write (f,a); {Перенесение i-й записи на место}

{(m-l)-i-ft}

Seek(f,i); {Установка указателя на i-ю запись}

Write (f,b); {Перенесение (п-1)Ч-й записи на место i-й}

End;

Trancate (f); {Отсечение половины записей}

Close (f);

End.

Безусловно, проще было бы обратить массив А в ОП, а затем перенести его в файл. Приведенная программа показывает лишь возможности использования стандартных процедур и функций.

 
< Пред   СОДЕРЖАНИЕ     След >