250 CLOSE 'иначе закрываем файл
Средний уровень.
Kак и все другие операции с файлами в MS DOS имеется два мето-
да записи в файл прямого доступа, один с использованием управляю-
щего блока файла, а другой с помощью дескриптора файла. В обоих
случаях Вы должны создать буфер обмена данными, размер которого
должен быть не меньше, чем размер записи.
Метод управляющего блока файла:
Откройте управляющий блок файла с помощью функции 0FH и пусть
DS:DX указывают на него. После того как файл открыт поместите
номер записи для прямого доступа в поле записи прямого доступа
FCB. Затем вызовите функцию 22H прерывания 21H, которая пердаст
данные из DTA в файловый буфер, созданный при создании FCB. Дан-
ные могут не быть немедленно записаны на диск, если размер записи
меньше чем размер буфера. Реальная запись на диск будет происхо-
дить тогда, когда очередной вызов функции 22H заполнит буфер.
При возврате из функции 22H AL будет содержать 00, если обмен
прошел успешно. В противном случае в нем будет 1, если не хватает
пространства на диске и 2 - если область переноса мала для того,
чтобы записать одну запись (т.е. если размер буфера, установлен-
ный системой меньше, чем тот, который указан в FCB).
;---в сегменте данных
FCB DB 1, 'NEWDATA ', 25 DUP (0)
DTA DB 256 DUP (?)
;---открываем файл и устанавливаем поля FCB
MOV AH,0FH ;номер функции
LEA DX,FCB ;DS:DX указывают на FCB
MOV BX,DX ;копируем смещение для FCB
INT 21H ;открываем файл
MOV AX,256 ;размер записи
MOV [BX]+14,AX ;помещаем в поле размера записи
MOV AX,233 ;номер записи
MOV [BX]+33,AX ;помещаем в поле номера записи
MOV AX,0 ;обнуляем старший байт этого слова
MOV [BX]+35,AX ;
;---перенос данных из DTA в файл
MOV AH,22H ;номер функции записи с прямым доступом
LEA DX,FCB ;DS:DX указывают на FCB
INT 21H ;записываем данные
CMP AL,0 ;проверка на ошибку
JNE WRITE_ERROR ;
;---позднее, закрываем файл
LEA DX,FCB ;DS:DX указывают на FCB
MOV AH,10H ;функция закрытия файла
INT 21H ;закрываем файл
CMP AL,0FFH ;проверка на ошибку
JE CLOSE_ERROR ;
Часто программа работает сразу с набором записей прямого дос-
тупа, передавая их в память и из памяти как единое целое. MS DOS
предоставляет специальную функцию для этого при использовании
метода FCB, называемую запись блока с прямым доступом. Это функ-
ция 28H прерывания 21H. При входе DS:DX должны указывать на отк-
рытый FCB, в котором поле записи прямого доступа должно быть
равно номеру первой из записываемых записей набора. Эта функция
совершенно аналогична вышеприведенному примеру. Единственное
отличие (кроме номера функции) состоит в том, что в CX должно
быть указано число записей в блоке (не путайте эти "блоки" с
блоками по 128 записей, с помощью которых система находит требуе-
мую запись - программа может читать любое число записей, начиная
с любого места).
В CX возвращается число реально прочитанных записей. AL будет
содержать 0, если все записи успешно записаны, 1 - если не хва-
тает пространства на диске, при этом не будет записана ни одна
запись. В отличии от функции 22H эта функция автоматически увели-
чивает поля текущей записи, текущего блока и записи прямого дос-
тупа в FCB, так что они будут указывать на запись, следующую за
последней прочитанной. Отметим, что если при выполнении этой
функции установить CX = 0, то размер файла будет установлен в
соответствии с числом записей, равным полю записи прямого досту-
па, и таким образом можно резервировать для файла дисковое прост-
ранство.
Метод дескриптора файлов:
При использовании для доступа метода дескриптора файлов систе-
ма не различает последовательные файлы и файлы прямого доступа.
Ваша программа должна вычислить позицию в файле, с которой начи-
нается требуемая запись, и установить на нее файловый указатель.
Файловый указатель позиционируется с помощью функции 42H прерыва-
ния 21H. Поместите номер файла в BX, а смещение в файле в CX:DX
(CX будет содержать старший байт значения). Затем поместите в AL
кодовый номер от 0 до 2. При AL = 0, указатель будет установлен
со смещением CX:DX байтов относительно начала файла; при AL = 1,
указатель будет установлен со смещением CX:DX относительно теку-
щей позиции, а при AL = 2, указатель будет установлен со смеще-
нием CX:DX относительно конца файла (т.е. таким образом файл
будет расширен). Отрицательные числа недопустимы в качестве сме-
щений. При возврате DX:AX будут содержать новое положение указа-
теля (старший байт в DX). Если устанавливается флаг переноса, то
произошла ошибка. В этом случае AX будет содержать 1, если указан
неверный код в AL и 6 - если указан неверный номер файла.
После позиционирования файлового указателя запись прямого
доступа записывается с помощью той же функции 40H прерывания 21H,
которая использовалась для записи в последовательный файл. При
входе BX содержит номер файла, а CX - число байтов, которое надо
записать. При возврате AX будет содержать число реально записан-
ных байтов. Если оно отличается от числа помещенного в CX, то
вероятно диск полон (см. [5.1.4]). Kак обычно, при возникновении
ошибки устанавливается флаг переноса. В этом случае AX будет
содержать 5 при ошибке накопителя и 6 - если указан неверный
номер файла.
Файловый указатель играет ту же роль для образа файла на дис-
ке, что DTA для образа файла в памяти. Он может сдвигаться как
угодно для доступа к различным частям файла. Будьте внимательны,
манипулируя файловым указателем при работе с фалом прямого досту-
па, содержимое любого поля любой записи может быть сразу прочита-
но с диска и помещено в требуемое место в памяти.
;---в сегменте данных
HANDLE DW ? ;номер файла
FILEPATH DB 'A:NEWDATA',0 ;строка пути к файлу
REC_BUFFER DB 30 DUP (?) ;буфер выводимых записей
;---открываем файл
MOV AH,3DH ;номер функции
MOV AL,1 ;код открытия для записи
LEA DX,FILEPATH ;DS:DX указывают на путь
INT 21H ;открываем файл
JC OPEN_ERROR ;проверка на ошибку
MOV HANDLE,AX ;сохраняем номер файла
;---вычисляем позицию записи и устанавливаем файловый указатель
MOV AX,30 ;размер записи 30 байтов
MOV CX,54 ;номер записи #54 (55-я запись)
MUL CX ;теперь смещение для нее в DX:AX
MOV CX,DX ;помещаем старшее слово в DX
MOV DX,AX ;помещаем младшее слово в CX
MOV AL,0 ;устанавливаем указатель на начало
MOV AH,42H ;функция установки указателя
MOV BX,HANDLE ;номер файла
INT 21H ;устанавливаем указатель
JC POINTER_ERROR ;проверка на ошибку
;---пишем запись с прямым доступом
MOV AH,40H ;номер функции
MOV BX,HANDLE ;номер файла
MOV CX,30 ;размер записи
LEA DX,REC_BUFFER ;DS:DX указывают на буфер
INT 21H ;пишем запись
JC WRITE_ERROR ;проверка на ошибку
В отличии от метода FCB метод дескриптора файлов не предостав-
ляет специальной функции для записи блока записей прямого досту-
па. Однако Вашей программе необходимо только вычислить количество
байтов, составляющих блок записей, которое должно быть записано.
5.4.6 Чтение из файлов прямого доступа.
Чтение файлов прямого доступа является обратным процессом по
отношению к их записи. MS DOS вычисляет позицию в файле на диске,
затем считывает запись и помещает ее в память. Затем программа
должна разделить запись на поля в точности того же размера, кото-
рый был использован при конструировании записи. Hе забудьте уда-
лить символы пробела, добавленные при заподнении полей. Обсужде-
ние записи данных в файлы прямого доступа [5.4.5] содержит инфор-
мацию, которая поможет Вам лучше понять информацию данного разде-
ла.
Высокий уровень.
Для чтения файла прямого доступа необходимо открыть файл и
определить поля записи, как объяснено в разделе, относящемся к
записи в файлы прямого доступа. Затем надо использовать оператор
GET# для чтения определенной записи с диска. GET #1,23 считывает
запись номер #23 из файла, открытого под номером #1. При чтении
записи переменной, именованной в операторе FIELD, автоматически
присваивается соответствующее значение из записи. Hапример, если
оператор FIELD имеет вид FIELD 1, 20 AS X$, 2 AS Y$, то после
выполнения оператора GET 1,23 переменной X$ будет присвоено зна-
чение первых 20-ти байтов записи 23, а переменной Y$ - следующих
10-ти байтов. Операторы, аналогичные RSET и LSET для выделения
полей данных отсутствуют.
В случае числовых полей, напоминаем, что они должны быть
преобразованы в строковый вид с помощью функций MKI$, MKS$ и
MKD$. Для восстановления их оригинальных значений, с тем чтобы
над ними можно было проводить операции и печатать их, надо преоб-
разовать эти строки с помощью функций CVI, CVS и CVD. Если Y$
содержит целое число, то для выполнения обратного преобразования
запишите Y% = CVI(Y$), при этом переменная Y% будет содержать
значение, которое имела переменная перед тем как она была спе-
циально обработана для записи в файл прямого доступа. Если Вы
выведете строковое значение переменной, то увидите, что это число
в интервале от 0 до 65535, закодированное в два символа ASCII.
В данном примере открывается файл, созданный в примере пункта
[5.4.5], и выводится содержимое любой из затребованных записей:
100 OPEN "A:NEWDATA" AS #1 LEN = 24 'открываем файл
110 FIELD 1, 18 AS LASTNAME$, 2 AS AGE$, 4 AS WEIGHT$
120 CLS: INPUT "What is the record number";R 'запрос записи
130 IF R*24 > LOF(1) THEN BEEP: PRINT"No such record": GOTO 120
140 GET #1,R 'читаем запись из файла
150 PRINT LASTNAME$, CVI(AGE$), CVS(WEIGHT$) 'выводим ее
160 PRINT: PRINT "Do another (y/n)?" 'будем повторять?
170 C$ = INKEY$: IF C$ = "" THEN 170 'ожидаем ввода
180 IF C$ = "y" OR C$ = "Y" THEN 120 'повторяем, если надо
190 CLOSE 'иначе закрываем файл
Средний уровень.
Метод FCB доступа к файлам имеет две функции для чтения запи-
сей с прямым доступом. С другой стороны, метод дескриптора файлов
использует ту же функцию, что и для чтения последовательных фай-
лов. Два метода доступа рассматриваются отдельно.
Метод FCB:
Функция 21H прерывания 21H читает одну запись из файла прямого
доступа. Вторая функция, 27H, читает блок последовательных запи-
сей. Создайте управляющий блок файла, как показано в [5.3.5] и
откройте его [5.3.3]. После того как FCB открыт, введите в него
значения полей размера записи (DW по смещению 14) и номера записи
прямого доступа (DD по смещению 33). Если DS:DX указывают на
первый байт FCB, то можно вызывать функцию 21H для чтения записи
и запись будет помещена в паямть, начиная с первого байта DTA.
Если запись успешно прочитана, то в AL будет возвращен 0.
Однако при этом нет гарантии, что чтение прошло без ошибок, пос-
кольку неверный размер записи может привести к тому, что части
прилегающих записей будут считаны, как будто это одна запись.
Если запрошена запись с номером большим, чем число записей в
файле, то в AL будет возвращено 1 или 3. Если был возвращен код
3, то был считан самый конец файла и была прочитана часть записи
данных. Если был возвращен код 1, то данные вообще не были счита-