16.4.1. Типы и константы модуля DOS для работы с файлами
Для обеспечения работы процедур первых двух групп в модуле DOS вводятся специальные типы и константы. Так, для ввода атрибутов файла или их анализа определены константы
CONST
ReadOnly = $01; { только для чтения }
Hidden = $02; { скрытый файл }
SysFile = $04; { системный (непереносимый) }
VolumeID = $08; { метка диска }
Directory = $10; { подкаталог }
Archive = $20; { архивный (для BACKUP) }
AnyFile = $3F; { сумма всех предыдущих }
При использовании их можно складывать. Так, имя файла имеет шестнадцать вариантов композиций атрибутов ReadOnly, Hidden, SysFile, Archive; имя подкаталога может быть скрытым и т.п. Не стоит только суммировать что-либо с константой AnyFile, ибо она уже есть сумма всех предыдущих.
Для процедур FindFirst и FindNext введен тип SearchRec:
TYPE
SearchRec = RECORD
Fill : Array[1..21] of Byte; {системное поле }
Attr : Byte; {поле атрибута }
Time : LongInt; {запись времени }
Size : Longlnt; {размер файла }
Name : String[12]; {имя файла }
END;
Поля переменной этого типа содержат информацию по последнему найденному имени файла или подкаталога. Кроме того, предопределены еще две записи для поддержания работы с файлами. Для всех
- 358 -
файлов (типизированных или бестиповых), кроме текстовых, имеется системный тип:
TYPE
FileRec = RECORD
Handle : Word;
Mode : Word;
RecSize : Word;
Private : Array [1..26] of Byte;
UserData : Array [1..16] of Byte;
Name : Array [0..79] of Char;
END;
Поле Handle содержит специальную информацию для файловых функций MS-DOS. Поле Mode типа Word хранит специальное число, характеризующее состояние файла. Для работы с этим полем определены четыре константы (и только их значения могут содержаться в этом поле):
CONST
fmClosed = $D7B0; { файл закрыт }
fmInput = $0781; { текстовый файл открыт для чтения }
fmOutput = $D782; { текстовый файл открыт для записи }
fmInOut - $D7B3; { нетекстовый файл открыт для доступа }
{Все прочие значения говорят, что файл ни с чем не связан. }
Сравнивая значения констант со значением поля Mode, можно определить текущий статус файла.
Следующее поле записи FileRec — RecSize — содержит длину записи файла (она определяется типом компонентов файла). Для бестиповых файлов она устанавливается процедурами Rewrite или Reset, а для текстовых — процедурой SetTextBuf.
Поле Private, состоящее из 26 байт, зарезервировано и не используется, зато поле UserData может содержать практически любую информацию размером до 16 байт. Оно играет роль комментария к файлу. Здесь уместно напомнить, что основное назначение типа FileRec — обслуживание внутренних процессов языка. Из полей можно извлекать информацию, но запись в них может привести к непредсказуемым, а то и фатальным последствиям. (Исключение составляет процесс написания собственных драйверов текстовых файлов, что требует весьма высокой квалификации и знания «внутренностей» MS-DOS.) Поле UserData — единственное безопасное в этом плане.
Последний компонент записи FileRec — поле Name, которое содержит полное имя физического файла на диске. Заметим, что тип
- 359 -
имени не соответствует типу строки, и вдобавок к этому имя заканчивается символом #0.
Все сказанное выше относилось к нетекстовым файлам. Для текстовых файлов используется запись с другой структурой:
TYPE
TextBuf = Array[0..127] of Char; { стандартный буфер }
TextRec = RECORD
Handle : Word;
Mode : Word; { состояние файла fmXXX }
BufSize : Word; { размер буфера }
Private : Word;
BufPos : Word;
BufEnd : Word;
BufPtr : ^TextBuf; { адрес буфера в памяти }
OpenFunc : Pointer; { адреса драйверов: }
InOutFunc: Pointer;
FlushFunc: Pointer;
CloseFunc: Pointer;
UserData : Array [1..16] of Byte;
Name : Array [0..79] of Char;
Buffer : TextBuf;
END;
Первые поля имеют тот же смысл, что и для нетекстовых файлов. Поле Mode может содержать те же значения констант. Дополнительные поля отведены для работы с текстовым буфером, а группа полей типа Pointer содержит адреса функций — драйверов текстовых файлов. Если в них не записаны адреса своих текстовых драйверов, то принимаются системные.
Кроме случаев создания собственных драйверов, следует избегать внесения изменений в поля записи (кроме поля UserData). Это требование остается и для текстовых файлов.
Если кого-либо заинтересовала возможность использования системной информации о файлах, то обязательно появится вопрос: а как к ней добраться? Ни одна функция или процедура языка не имеет аргумента типа FileRec или TextRec. Создание переменной таких типов будет пустой тратой памяти. Оказывается, что это и не нужно. Для работы с файлами необходимо объявлять их переменные, например:
VAR
tf : Text; { текстовый файл }
fr : File of Real; { файл вещественных чисел }
f : File; { бестиповый файл }
- 360 -
Предопределено, что структура типа File и File of... соответствует типу FileRec (размер 128 байт), а типа Text — типу TextRec (paзмер 256 байт). Используя операцию преобразования типов, легко опросить любое поле системного типа. Примеры этого:
if TextRec( tf ).Mode = fmOutput then ... ;
if FileRec( fr ).Mode <> fmlnOut then ... ;
ByteVAR := FileRec( f ).UserData[4];
и т.п. Пример извлечения имени файла из записи:
StringVAR := ' '; i := 0; { имя файла }
repeat
StringVAR := StringVAR + TextRec( tf ).Name[i];
Inc( i )
until StringVAR[i]=#0;
...
Работая таким образом с файловыми переменными, следует всегда помнить, что файловая переменная f перед анализом обязательно должна «пройти» через процедуры Assign (f, имя физического файла) и Reset или Rewrite. В противном случае поля типов будут содержать в буквальном смысле что угодно, кроме полезной информации.
Возможное применение описанных записей — анализ состояния конкретных файлов через поле Mode, добавление комментариев в поле UserData. Это достаточно полезно и относительно несложно. Но основное их назначение — подключение собственных файловых драйверов. Этот вопрос слишком сложен и в этой книге не рассматривается.
Зато все вышеизложенное можно с пользой применять при отладке программ в среде Турбо Паскаль. Если, например, непонятно, что творится с логическим текстовым файлом MyFile, то можно поместить его в окно отладчика Watch в преобразованном виде:
TextRec( MyFile ), R
И при трассировке поля записи будут заполняться внутренними параметрами. Подобный фокус можно провести и с окном опроса Evaluate.
Для третьей группы (процедуры FSplit и функции FExpand) вводятся специальные типы для ведения имен файлов и подкаталогов:
- 361 -
TYPE
ComStr = String [127]; { для командной строки }
PathStr = String [79]; { для полного имени файла }
DirStr = String [67]; { для маршрута на диске }
NameStr = String [8]; { только имя файла }
ExtStr = String [4]; { точка и расширение }
Для работы с процедурами поисков файлов и анализа имен необходимо вводить переменные именно таких типов. Размеры строк в типах соответствуют ограничениям MS-DOS на длину имен и маршрутов.
Для работы с файлами может также пригодиться системная переменная модуля DOS — DosError.