До сих пор мы рассматриваем форматы, размещающие и форматирующие одновременно. Но когда длина значения заранее неизвестна, размещение-выравнивание по правому краю может дать некрасивые форматы:
Короткое число в формате 10 = 12
Длинное число в формате 10 = 12345678
Можно задать выравнивание по левому краю. В этом случае значение форматируется (если оно числовое) и пишется без предшествующих пробелов: сразу с текущей позиции. При этом занимается поле, равное длине значения. Никаких пробелов справа уже не дописывается:
Короткое число в формате -10 = 12
Длинное число в формате -10 = 12345678
Для задания такого режима надо ближнюю к значению спецификацию формата задавать отрицательной:
Write( 123.456 : 6 : 1, 22 : 4 ); { ' 123.5' и ' 22' }
Write( 123.456 :-6 : 1, 22 :-4 ); { '123.5' и '22' }
Несмотря на некоторое отсутствие гибкости в способе задания формата (нельзя задавать форматы-шаблоны — как в Фортране, Бейсике, а надо описывать каждое значение), механизм форматированного вывода текстовой информации Турбо Паскаля достаточно мощный. Помните только, что форматы имеют смысл лишь при работе с текстовыми файлами. Во всех остальных случаях они неприменимы.
12.7. Типизированные файлы и операции ввода-вывода
Типизированный, или компонентный, файл — это файл с объявленным типом его компонентов, т.е. файл с наборами данных одной и той же структуры. Как и в стандарте Паскаля, объявление такого файлового типа имеет структуру
File of ТипКомпонента,
- 246 -
где компонент может иметь любой ординарный или структурированный тип, предопределенный или построенный программистом. Запрещено лишь объявлять файлы файлов и файлы объектов, а также файлы структурированных компонентов (массивов, записей и др.), содержащих те же файлы или объекты. Так, допустимы следующие объявления:
TYPE
DimComp = Array [1..100,1..2] of Real;
RecComp = RECORD
X,Y : Byte;
A : DimComp
END;
DimFile = File of DimComp;
RecFile = File of RecComp;
IntFile = File of Integer;
Но компилятор не пропустит такие типы:
TYPE
FileFilel = File of File of Real; { неверно: файл файлов }
FileFile2 = File of DimFile; { неверно: файл файлов }
FRecComp = RECORD
X,Y : Byte;
F : File of Char
END;
FRecFile = File of FRecComp; { нельзя: файл в компоненте!}
ObjComp = OBJECT
...
END;
ObjFile = File of ObjComp; { неверно: файл объектов }
При написании программ необязательно определять специальные файловые типы. Это можно сделать «на ходу» при описании переменных:
VAR
FR : File of Real;
FD : File of DimComp;
Для работы с объявленным файлом необходимы обычные предварительные действия: связывание файловой переменной с физическим файлом и открытие файла для чтения или записи, например:
Assign( FR, 'RFILE.DAT' ); Reset( FR );
Assign( FD, 'DFILE.DAT' ); Rewrite( FD );
- 247 -
Для типизированных файлов обе процедуры Reset и Rewrite устанавливают режим «чтение/запись» в соответствии со значением предопределенной системной переменной FileMode (оно по умолчанию равно 2), т.е. независимо от выбора процедуры открытия, файл открывается и для чтения, и для записи. Это верно только для типизированных и бестиповых файлов, но ни в коем случае, не для текстовых. Этот порядок нарушится только в том случае, когда значение FileMode соответствует режиму «только запись» (1) или «только чтение» (0). Сменить режим можно простым присваиванием нужного значения переменной FileMode перед открытием файла. После этого вызов Reset будет открывать файл в заданном режиме, даже если он будет «только запись»! Процедура Rewrite также должна «слушаться» указаний FileMode, но только в том случае, когда файл уже существует. Для новых файлов Rewrite всегда включает режим «чтение/запись».
На практике редко возникает необходимость вмешиваться в стандартный порядок работы процедур. Более того, лучше использовать те процедуры, которые более соответствуют смыслу программы.
После открытия файла ввод и вывод данных осуществляется стандартными операторами
Read( f, х ) и Write( f, x )
или
Read( f, х1, х2, хЗ,...,xn) и Write(f, х1, х2, хЗ,..., xn).
Первым аргументом должно быть имя логического файла f, с которым связан конкретный физический файл. А далее должна стоять переменная (или их список) того же типа, что и объявленный тип компонента файла f, в которую запишется очередное значение из файла при чтении (Read) или, наоборот, которая запишется в файл (Write).
В отличие от файлов типа Text типизированные файлы имеют более строгую внутреннюю структуру. При записи в них записывается машинное представление очередного компонента, будь то число, массив, запись или строка. Внутри файла компоненты не отделяются ничем друг от друга (тем не менее найти любой компонент несложно: каждый из них занимает в файле одинаковый объем, равный размеру его типа). Поэтому не имеет смысла применять к типизированным файлам операторы ReadLn и WriteLn. В них просто не существует такого понятия, как строка и ее конец, и нет признака конца файла (конец определяется длиной файла). Даже если объявить файл как
- 248 -
VAR