зуемых файлом). Файл должен быть открыт и ссылаться на него надо
по номеру, под которым был открыт файл. Формат X = LOF(1). В
следующем примере определяется сколько 64-байтных записей содер-
жится в файле, открытом как #3:
100 OPEN "FILENAME" AS #3 'открываем файл
110 RECORDLEN = 64 'определяем длину записи
120 NUMBREC = LOF(3)/RECORDLEN 'вычисляем число записей
Средний уровень.
FCB функция 23H прерывания 21H сообщает число записей в файле.
Если приписать файлу длину записи в 1 байт, то его размер будет
возвращен в байтах. DS:DX должны указывать на управляющий блок
открытого файла. Затем вызовите функцию. Если файл не найден, то
в AL возвращается FF. В противном случае в AL возвращается 0, а
число записей помещается в поле номера записи прямого доступа FCB
(байты 33-36). Для правильной работы поле длины записи FCB должно
быть установлено после открытия файла, но перед вызовом функции;
это двухбайтное поле расположено по смещению 14 в FCB. Если раз-
мер файла неточно делится на длину записи, то сообщаемое число
записей округляется вверх. Вот пример, в котором используется
длина записи равная 1:
;---определение размера файла
LEA DX,FCB ;DS:DX указывает на FCB
MOV BX,DX ;копируем указатель в BX
MOV CX,1 ;размер записи в CX
MOV [BX]+14,CX ;пишем в поле размера записи FCB
MOV AH,23H ;функция сообщающая размер файла
INT 21H ;вызов функции
MOV AX,[BX]+33 ;получаем младшую часть размера файла
MOV CX,[BX]+35 ;получаем старшую часть размера файла
Можно также устанавливать длину файла, используя управляющие
блоки файла. Для этого надо использовать функцию записи блока с
прямым доступом, которая обсуждается в [5.4.5]. У этой функции
имеется частный случай, когда число записанных записей устанавли-
вается равным нулю, то длина файла устанавливается равной числу
записей, указанному в поле записи прямого доступа.
Метод, использующий дескриптор файла (file handle) не имеет
функции, которая непосредственно сообщала бы длину файла, однако
имеется возможность вычислить размер, передвинув указатель файла
с начала на конец файла. При открытии файла указатель файла авто-
матически устанавливается на первый байт файла. Указатель файла
перемещается функцией 42H прерывания 21H. Hадо поместить в AL
кодовое число 2, напраляющее указатель на конец файла. В BX дол-
жен быть указан номер файла, а CX:DX содержит смещение от конца
файла до позиции, в которую должен быть установлен указатель,
поэтому поместите 0 в оба этих регистра. Затем вызовите функцию.
При возврате DX:AX будет содержать новую позицию указателя, отно-
сительно его предыдущей позиции - т.е. будет содержать длину
файла (DX содержит старший байт). При возникновении ошибки будет
установлен флаг переноса, а в AX будет возвращено 1, если непра-
вилен номер функции и 6, если неправилен номер файла. Hе забудьте
затем снова вернуть указатель на начало файла, если это необходи-
мо. Поместите 0 в AL, CX и DX и вызовите функцию снова. Вот при-
мер:
;---открываем файл
LEA DX,FILE_PATH ;DS:DX указывают на путь файла
MOV AL,0 ;открываем для чтения
MOV AH,3DH ;функция открытия файла
INT 21H ;открываем его
JC OPEN_ERROR ;проверка на ошибку
MOV HANDLE,AX ;запоминаем номер файла
;---определяем длину файла
MOV AH,42H ;функция перемещения указателя
MOV AL,2 ;код установки на конец файла
MOV BX,HANDLE ;номер файла в BX
MOV CX,0 ;0 в CX и DX
MOV DX,0 ;
INT 21H ;сдвигаем указатель
JC POINTER_ERROR ;ошибка?
MOV FSIZE_HIGH,DX ;запоминаем размер файла
MOV FSIZE_LOW,DX ;
5.1.4 Восстановление после ошибок, связанных с нехваткой
пространства на диске.
При попытке записи на полный диск может произойти крах прог-
раммы. Часто легко избежать этого, даже в Бейсике, проверив пред-
варительно наличие дискового пространства [5.1.2]. Однако, если
ошибка произошла, то постарайтесь дать пользователю возможность
исправить ее. Позвольте ему сохранить только часть данных или
стереть какой-нибудь другой файл и повторить попытку. Или, еще
более радикальное средство, позвольте пользователю вставить дру-
гую дискету. Последний подход должен реализовываться с большой
осторожностью. Сначала закройте все открытые файлы. Затем выдайте
запрос на смену дискеты. После того, как пользователь сообщит,
что новая дискета на месте, создайте новый файл и запишите туда
данные.
Высокий уровень.
В Бейсике надо установить процедуру обработки ошибок, как
показано в [7.2.5]. Если оператор Бейсика делает попытку писать
на полный диск, то возвращается код ошибки #61. При этом управле-
ние может быть передано процедуре обработки ошибок, которая ин-
формирует пользователя о проблеме и позволяет ему справиться с
ней, не теряя данных.
100 ON ERROR GOTO 5000 'разрешаем обработку ошибок
.
.
200 OPEN FNAME$ FOR OUTPUT AS #1 'открываем файл
210 FOR N = 1 TO ARRLEN 'начинаем писать массив на диск
220 PRINT #1, ARRAY$(N) 'записываем один элемент
230 NEXT '
.
.
5000 IF ERR = 61 THEN 5100 'диск полон?
5100 IF ERR = ... 'другие ошибки ...
.
5100 '''восстановление при переполнении диска
5110 BEEP: PRINT "Disk full - choose an option:"
5120 PRINT "(A) - Re-edit the file"
5130 PRINT "(B) - Delete some other file from disk"
5140 PRINT "(C) - Use different diskette"
. (здесь идет процедура восстановления)
.
5500 RESUME
Средний уровень.
Все функции DOS, которые пишут на диск, выдают определенный
код ошибки при попытке записи на полный диск. Вот сводка этих
кодов:
Метод доступа Функция Hазвание Kод ошибки
FCB 15H Последовательная запись AL = 1
FCB 22H Прямая запись AL = 1
FCB 27H Прямая запись блока AL = 1
Дескриптор 40H Запись в файл/устройство CX <> BX
Проверяйте эти ошибочные условия после каждой записи на диск.
Поскольку критической ошибки не происходит, то восстановление не
вызывает проблем. Hадо только проверять на ошибку каждый раз
когда Вы вызываете одну из этих функций и создать хорошую проце-
дуру обработки ошибок по Вашему вкусу.
Раздел 2. Работа с каталогами диска.
Kаждый диск имеет один корневой каталог, с которого начинается
поиск всех остальных каталогов. Kорневой каталог может содержать
элементы, указывающие на подкаталоги, которые в свою очередь
могут содержать ссылки на другие подкаталоги, образуя древовидную
структуру каталогов. Kорневой каталог всегда расположен в опреде-
ленных секторах диска; подкаталоги хранятся как обычные дисковые
файлы, поэтому они могут быть расположены в любом месте диска.
Отметим, что фиксированный диск может содержать до четырех корне-
вых каталогов, если он разбит на разделы, хотя MS DOS "видит"
только один корневой каталог. Kаталоги могут иметь различные
размеры, в зависимости от размера диска и его разбиения на разде-
лы. В следующей таблице приведены размеры и позиции корневых
каталогов для разных типов дисков:
Тип диска Размер каталога Число элементов Hачальный сектор
дискета 160K 4 сектора 64 9
дискета 180K 4 сектора 64 9
дискета 320K 7 секторов 112 15
дискета 360K 7 секторов 112 15
дискета 1.2M 14 секторов 224 29
жесткий 10M ----------переменные------------
жесткий 20M ----------переменные------------
В зависимости от разбиения на разделы фиксированный диск может
иметь различные размеры каталога и номер начального сектора. Если
весь диск отведен для MS DOS, то на XT и AT под корневой каталог
отводится 32 сектора, что позволяет иметь в нем 512 элементов.
Kак корневой каталог, так и подкаталоги, используют 32 байта
для хранения информации об одном файле, независимо от типа диска.
Таким образом в каждом секторе может храниться информация о 16-ти
элементах каталога. Kаждое 32-байтное поле разбито следующим
образом:
байты 0-7 Имя файла
8-10 Расширение файла
11 Атрибут файла
12-21 Зарезервировано
22-23 Время последнего доступа к файлу
24-25 Дата последнего доступа к файлу
26-27 Hачальный кластер
28-31 Размер файла
Точка между именем файла и его 3-байтным расширением не хранится.
Все поля выравнены на левую границу, а пустые байты заполняются
пробелами (код ASCII 32). Атрибут файла определяет является ли
файл спрятанным, защищенным от записи и т.д. [5.2.6]. Он опред-
ляет также специальные элементы каталога, такие как подкаталоги
или метка тома. Информация о времени и дате упакована, поэтому
для чтения этих значений требуются битовые операции [5.2.5].
Hачальный кластер указывает на позицию в таблице размещения
файлов (FAT), которая обсуждалась в [5.1.1]. FAT хранит информа-
цию о свободном пространстве на диске, а также отводит сектора
при записи файла. FAT отводит дисковое пространство порциями,
большими чем 1 сектор, которые называются кластерами. Файл распо-
ложен в цепочке кластеров и FAT содержит соответствующую цепочку
элементов, указывающих, где эти кластеры расположены на диске.
Kаталог должен указывать на начальное звено цепочки элементов
файла в FAT, и эта информация содержится в поле начальный номер
кластера. Поскольку файл обычно занимает последний отведенный ему
кластер не целиком, то поле размер файла хранит точную длину
файла в байтах.
5.2.1 Чтение/изменение корневого каталога.
Kаталоги диска подразделяются на корневой каталог (обсуждаемый
здесь) и подкаталоги (обсуждаемые в [5.2.3]). Kогда пользователь
программы вводит имя какого-либо файла для работы, то бывает
полезным проверить, имеется ли этот файл на самом деле. Обычно
изменения в корневом каталоге производятся в ходе обычных файло-
вых операций или с помощью специальных функций DOS. Однако можно
работать с каталогом напрямую. Большая нужда в таком подходе
возникает при работе на языках высокого уровня, где утилиты DOS
по большей части недоступны.
Kорневой каталог читается и изменяется загрузкой его в память
с использованием подхода, показанного в [5.4.2], когда читаются
абсолютные сектора диска. Эти операции не оставляют места между
секторами, когда они загружаются в память. Буфер, содержащий
данные сектора, может рассматриваться как набор 32-байтных полей
и пара указателей, которые могут использоваться для движения по
каталогу. Один указатель всегда кратен 32 и указывает на начало
элемента каталога. Второй указатель добавляется к первому и ука-
зывает на одно из полей в 32-байтном элементе. Данные в памяти
могут быть изменены требуемым образом, а затем весь буфер записы-
вается обратно на диск.
Имеется два метода чтения абсолютных секторов диска и в обоих
случаях только одно число отличает случаи чтения и записи. Пос-
кольку ошибка при записи на диск может легко повредить все содер-
жимое диска, то надо действовать аккуратно. Сначала убедитесь,
что операция чтения сектора выполнена верно во всех отношениях.
После этого можно попробовать записать на диск, взяв точную копию
кода, использованного для чтения и заменив только номер функции.
Высокий уровень.
Бейсик выводит каталог по команде FILES. При этом выводятся
только имена файлов. FILES дает каталог накопителя по умолчанию;
для указания накопителя напишите FILES "A:" и т.д. Можно потребо-
вать, чтобы была выведена информация об отдельном файле, написав