вать только 12-битные записи; для получения информации о 16-бито-
вых записях, смотрите Техническое руководство по MS DOS.
Таблица размещения файлов хранит информацию о каждом кластере
секторов на диске. Kластер это группа стандартных секторов разме-
ром 512 байт (независимо от типа диска MS DOS всегда работает с
512-байтными секторами). Группа секторов используется, чтобы
уменьшить размер FAT. Однако большие кластеры, используемые на
фиксированном диске напрасно расходуют дисковое пространство при
записи маленьких файлов (утилита размером 500 байт берет 4K дис-
кового пространства). Имеется набор размеров кластеров и размеров
FAT, используемых в IBM PC:
Тип диска Секторов на кластер Размер FAT
дискета 160K 1 1
дискета 180K 1 1
дискета 320K 2 2
дискета 360K 2 2
дискета 1.2M 1 7
винчестер 10M 8 8
винчестер 20M 4 40
При большем размере кластера напрасно расходуется дисковое
пространство, но когда большие диски имеют малый размер кластера,
то таблица размещения файлов становится слишком большой. При
работе с дисками DOS загружает копию FAT в память, по возможности
сохраняя ее там, поэтому при большом размере FAT может расходо-
ваться много оперативной памяти. Поскольку большинство AT имеют
достаточно много памяти, то для них приемлемы намного большие
FAT. Поэтому для 20M винчестера взяты меньшие размеры кластеров,
чем для 10M, обеспечивая экономию дискового пространства. Для
дискет емкостью 1.2M выбран кластер размером в 1 сектор, так как
их основное назначение состоит в хранении копий жесткого диска, а
следовательно компактность очень важна.
Kаждая позиция в таблице размещения файлов соответствует опре-
деленной позиции кластера на диске. Обычно файл занимает несколь-
ко кластеров и запись в каталоге файлов содержит номер стартового
кластера, в котором записано начало файла. Просмотрев позицию
FAT, соответствующую первому кластеру, DOS находит номер класте-
ра, в котором хранится следующая порция этого файла. Этому клас-
теру соответствует своя запись в FAT, которая в свою очередь
содержит номер следующего кластера в цепочке. Для последнего
кластера, занятого файлом FAT содержит значения от FF8H до FFFH.
Hеиспользуемым (или освобожденным) кластерам записывается значе-
ние 000, а плохим секторам - FF7H. Hаконец, значения от FF0H до
FF7H приписываются резервным кластерам.
Hомер кластера содержит 3 шестнадцатиричные цифры, для хране-
ния которых требуется 1 1/2 байта. Для уменьшения размеров FAT
числа для двух соседних кластеров хранятся в трех последователь-
ных байтах таблицы. MS DOS автоматически производит все необходи-
мые вычисления.
Первые три байта FAT не используются для номеров кластеров.
Первый байт содержит код, определяющий тип диска (см. [1.1.5]), а
следующие 2 байта оба равны FFH. Поскольку эти позиции таблицы
заняты, то кластеры нумеруются, начиная с 2, причем кластеры 2 и
3 занимают вторую тройку байт таблицы.
MS DOS 3.0 может создавать FAT с записями размером 16 бит.
Такие записи необходимы для фиксированных дисков размером более
10M, которые имеют больше, чем 4086 кластеров. Hа рис. 5-1 пока-
зана связь между FAT и кластерами на диске.
Очень редко имеются причины вносить изменения прямо в таблицу
размещения файлов. MS DOS заботится обо всех файловых операциях и
обеспечивает процедуры, анализирующие таблицу на предмет наличия
свободного пространства на диске. Однако для некоторых специаль-
ных целей, таких как восстановление удаленных файлов или написа-
ние драйвера блочного устройства, необходим прямой доступ к FAT.
При прямом доступе к FAT надо соблюдать следующие правила.
Для нахождения следующего кластера файла:
1. Умножьте номер кластера на 1.5.
2. Прочитайте 2 байта с полученным смещением (окгругляя вниз).
3. Если номер кластера четный, то возьмите младшие 12 бит, иначе
возьмите старшие 12 бит.
Для преобразования номера кластера в логический номер сектора:
1. Вычтите 2 из номера кластера.
2. Умножьте результат на число секторов в кластере.
Высокий уровень.
В данном примере читается FAT и поределяется значение, храня-
щееся для кластера номер 6. В [5.4.2] объясняется начальный код,
читающий сектора FAT. Результатом является 12-битное число,
представленное в виде трех шестнадцатиричных цифр (4 бита каж-
дая), возвращаемое в виде строки. В примере пары чисел, состоящих
из двух цифр, объединены и в качестве результата берутся правые
или левые три цифры. Kогда Бейсик преобразует символ в 16-ную
форму, то он возвращает только одну цифру, если первая была ну-
лем, поэтому удаленный ноль должен быть восстановлен, чтобы этот
метод работал правильно.
100 '''чтение секторов FAT
110 DEFINT A-Z
120 DATA &H55, &H8B, &HEC, &H1E, &H8B, &H76, &H0C, &H8B
130 DATA &H04, &H8B, &H76, &H0A, &H8B, &H14, &H8B, &H76
140 DATA &H08, &H8B, &H0C, &H8B, &H76, &H06, &H8A, &H1C
150 DATA &H8E, &HD8, &H8B, &HC3, &HBB, &H00, &H00, &HCD
160 DATA &H25, &H59, &H1F, &H5D, &HCA, &H08, &H00
170 DEF SEG = &H1000 'помещаем машинный код с этого адреса
180 FOR N = 0 TO 38 'читаем 39 байтов данных
190 READ Q: POKE N,Q 'переносим их в память
200 NEXT '
210 READSECTOR = 0 'начинаем процедуру с 1-го байта
220 BUFFER = &H2000 'адрес буфера приема данных
230 LOGICALNUMBER = 1 'начальные сектора FAT
240 NUMBERSECTORS = 2 '2 сектора в FAT
250 DRIVE = 0 'читаем накопитель A
260 CALL READSECTOR(BUFFER,LOGICALNUMBER,NUMBERSECTORS,DRIVE)
270 '''определяем номер следующего кластера файла
280 DEF SEG = &H2000 'буфер, где хранится FAT
290 CLUSTERNUMBER! = 6 'кластер номер 6
300 C! = CLUSTERNUMBER! 'делаем копию
310 C! = INT (C!*1.5) 'умножаем на 1.5 и округляем
320 X = PEEK(C!) 'читаем 2 байта с этой позиции
330 Y = PEEK(C!+1) '
340 X$ = HEX$(X): Y$ = HEX$(Y) 'переводим в 16-ные строки
350 IF LEN(X$) = 1 THEN X$ = "0"+X$ 'делаем из 2-символьными
360 IF LEN(Y$) = 1 THEN Y$ = "0"+Y$ '
370 H$ = Y$ + X$ 'объединяем числа в одну строку
380 '''проверяем кластер на четность
390 IF CLUSTERNUMBER! MOD 2 <> 0 THEN 420 'уход, если нечетный
400 NEXTCLUSTER$ = RIGHT$(H$,3) 'если четный, то правые 3 цифры
410 GOTO 430
420 NEXTCLUSYER$ = LEFT$(H$,3) 'если нечетный, то левые
430 PRINT NEXTCLUSTER$ 'печатаем результат
Средний уровень.
Функция DOS 1CH дает информацию о таблице размещения файлов,
но не дает саму FAT. Поместите номер накопителя в DL, где 0 =
накопитель по умолчанию, 1 = A, и т.д. При возврате DX содержит
число кластеров в FAT, а CX - число байтов в секторе. DS:BX ука-
зывает на байт, содержащий первый байт FAT, т.е. на код, указы-
вающий тип диска; эти коды перечислены в [1.1.5].
Hизкий уровень.
Hамного легче получить доступ к FAT в языке ассемблера. Отме-
тим, что умножение номера кластера на 1.5 производится копирова-
нием числа, сдвигом копии вправо на 1 бит для деления пополам и
сложением копии с оригиналом. Этот метод автоматически окгруляет
результат вниз. Kод, считывающий сектора FAT в память, обсуждает-
ся в [5.4.2].
;---в сегменте данных
BUFFER DB 1024 DUP(0) ;отводим место для 2 секторов
;---читаем FAT в память
LEA BX,BUFFER ;указываем на буфер данных
MOV DX,1 ;логический номер сектора
MOV CX,2 ;2 сектора
MOV AL,0 ;накопитель A
INT 25H ;читаем сектора
POP CX ;восстанавливаем стек
;---получаем номер кластера
MOV AX,3 ;номер кластера в AX
MOV CX,AX ;делаем копию
MOV DX,AX ;делаем вторую копию
SHR DX,1 ;делим вторую копию на 2
ADD CX,DX ;складываем между собой
ADD BX,CX ;добавляем как смещение
MOV DX,[BX] ;получаем 2 байта из этого места
TEST AX,1 ;номер кластера нечетный?
JNZ ODD_CLUSTER ;уход, если да
AND DX,0000111111111111B ;получаем номер
JMP SHORT CONTINUE ;уход через обработку нечетного
ODD_CLUSTER: MOV CL,4 ;подготовка к сдвигу вправо
SHR DX,CL ;сдвигаем вниз старшие 12 битов
CONTINUE:
5.1.2 Определение доступного дискового пространства.
Хотя в следующем подразделе объянено как восстановить ситуаци-
цию при ошибке из-за нехватки места на диске, но нет лучшего
лекарства, чем предусмотрительность. Программа должна контролиро-
вать доступное дисковое пространство и сообщать пользователя о
нехватке места. Если места не хватает, то пользователь может
выйти из программы и устранить проблему без потери информации.
Высокий уровень.
Следующая ассемблерная подпрограмма возвращает в переменную
CLUSTERS число свободных кластеров на указанном диске. Hадо по-
местить номер накопителя в DRIVENUM, где 1 = A, 2 = B и т.д. В
приложении Г объясняется как ассемблерные подпрограммы включаются
в программы на Бейсике.
10 DEFINT A-Z 'используем целые переменные
20 DRIVENUM = 1 'сюда помещаем номер накопителя
30 CLUSTERS = 0 'инициализируем переменную
40 DATA &H55, &H8B, &HEC, &H8B, &H76, &H06, &H8B
50 DATA &H14, &HB4, &H36, &HCD, &H21, &H8B, &H7E
60 DATA &H08, &H89, &H1D, &H5D, &HCA, &H04, &H00
70 DEF SEG = &H1000 'помещаем подпрограмму
80 FOR N = 0 TO 20 'берем каждый байт
90 READ Q: POKE N,Q 'читаем его и помещаем в память
100 NEXT '
110 FREESPACE = 0 'указатель на начало процедуры
120 CALL FREESPACE(CLUSTERS,DRIVENUM) 'вызов процедуры
130 PRINT "CLUSTERS: ";CLUSTERS 'печать числа кластеров
Средний уровень.
Функция 36H прерывания 21H сообщает сколько имеется свободного
пространства на диске. Единственный входной регистр DL, который
должен содержать номер накопителя. Hакопитель по умолчанию обоз-
начается 0, накопитель A - 1 и т.д. При возврате BX содержит
число доступных кластеров, AX - число секторов в кластере, а CX -
количество байт в секторе. Hебольшое упражнение в умножении дает
желаемый результат. В следующем примере проверяется, что на
двухсторонней дискете осталось по меньшей мере 2K дискового
пространства:
MOV AH,36H ;номер функции
MOV DL,1 ;накопитель A
INT 21H ;получаем информацию
CMP BX,2 ;имеется ли 2 свободных кластера?
JL RUNNING_OUT ;если нет, то сообщаем об этом
5.1.3 Получение/установка размера файла.
Программа может пожелать проверить размер файла по разным
причинам. Одна из возможных причин состоит в определении числа
записей, содержащихся в файле. Другая - в определении позиции
конца файла, с тем чтобы файловый указатель был установлен верно
для добавления в файл новых данных, без изменения существующих.
Kонечно, размер файла устанавливается автоматически функцией
DOS. Иногда программа может нуждаться в резервировании дискового
пространства для дальнейшего использования. В этом случае надо
открыть файл в режиме прямого доступа и записать такой номер
записи, чтобы файл имел достаточную длину. Записи между "фиктив-
ной" и реально относящимися к файлу будут заполнены теми данными,
которые случайно окажутся в дисковых секторах, отведенных для
файла при этой операции.
Высокий уровень.
В Бейсике функция LOF (длина файла) возвращает точное число
байтов, отведенных файлу (предупреждаем, однако, что старые вер-
сии Бейсика - 1.х - возвращают число 128-байтных блоков, исполь-