Справочник программиста на персональном компьютере фирмы IBM. Дисковые накопители - Чтение из файлов прямого доступа
ОГЛАВЛЕНИЕ
5.4.6 Чтение из файлов прямого доступа.
Чтение файлов прямого доступа является обратным процессом по
отношению к их записи. MS DOS вычисляет позицию в файле на диске,
затем считывает запись и помещает ее в память. Затем программа
должна разделить запись на поля в точности того же размера, кото-
рый был использован при конструировании записи. Не забудьте уда-
лить символы пробела, добавленные при заподнении полей. Обсужде-
ние записи данных в файлы прямого доступа [5.4.5] содержит инфор-
мацию, которая поможет Вам лучше понять информацию данного разде-
ла.
Высокий уровень.
Для чтения файла прямого доступа необходимо открыть файл и
определить поля записи, как объяснено в разделе, относящемся к
записи в файлы прямого доступа. Затем надо использовать оператор
GET# для чтения определенной записи с диска. GET #1,23 считывает
запись номер #23 из файла, открытого под номером #1. При чтении
записи переменной, именованной в операторе FIELD, автоматически
присваивается соответствующее значение из записи. Например, если
оператор 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, то данные вообще не были счита-
ны.
Данный пример считывает одну запись и помещает ее в DTA:
;---в сегменте данных
FCB DB 1,'OLDDATA ', 25 DUP (0)
;---открываем файл и устанавливаем поля FCB
MOV AH,0FH ;номер функции
LEA DX,FCB ;DS:DX указывают на FCB
MOV BX,DX ;копируем смещение FCB
INT 21H ;открываем файл
MOV AX,55 ;размер записи 55 байтов
MOV [BX]+14,AX ;помещаем в поле размера записи
MOV AX,22 ;номер записи для чтения
MOV [BX]+33,AX ;помещаем в поле номера записи
MOV AX,0 ;обнуляем старшее слово этого поля
MOV [BX]+35,AX ;
;---перенос данных из файла в DTA
MOV AH,21H ;номер функции чтения с прямым доступом
LEA DX,FCB ;DS:DX указывают на FCB
INT 21H ;читаем данные, помещая их в DTA
CMP AL,0 ;проверка на ошибку
JNE READ_ERROR ;
;---позднее, закрываем файл
MOV AH,10 ;номер функции закрытия файла
LEA DX,FCB ;DS:DX указывают на FCB
INT 21H ;закрываем файл
Для чтения блока последовательных записей в память за один
прием надо использовать функцию 27H прерывания 21H. Ее выполнение
подготавливается в точности так же, как и функции 21H, за исклю-
чением того, что вдобавок CX должен содержать число записей кото-
рые надо прочитать за один прием. При возврате CX будет содержать
число реально прочитанных записей. Значения возвращаемые в AL
совпадают с теми, которые возвращаеются функцией 21H. В отличии
от функции 21H поля FCB, в которых хранится информация о положе-
нии записи (поле записи прямого доступа, текущего блока и текущей
записи) автоматически увеличиваются, с тем чтобы они указывали на
следующую несчитанную запись после выполнения функции.
Отметим, что как в случае чтения одной, так и в случае чтения
нескольких записей, поля текущего блока и текущей записи FCB
устанавливаются по значению поля записи прямого доступа. Если Вы
знаете значение текущего блока и текущей записи, а не соответст-
вующий номер записи прямого доступа, то используйте функцию 24H
прерывания 21H, чтобы она проделала вычисления за Вас. У этой
функции нет входных регистров, надо только, чтобы DS:DX указывали
на открытый FCB. При возврате поле записи прямого доступа будет
заполнено значением, соответствующим установке двух других полей.
Метод дескриптора файлов:
В предыдущем разделе показано, как писать записи прямого дос-
тупа с помощью метода дескриптора файлов. Процедура чтения из
файла с прямым доступом подготавливается совершенно аналогичным
образом, путем вычисления смещения в файле, на которое должен
указывать файловый указатель. DS:DX должны указывать на буфер, в
который будет помещена запись, после чего надо выполнить функцию
3FH прерывания 21H. При входе CX должен содержать размер записи,
а BX - номер файла.
;---в сегменте данных
HANDLE DB ?
FILEPATH DB 'A:OLDDATA',0
REC_BUFFER DB 30 DUP(?)
;---открываем файл
MOV AH,3DH ;номер функции
MOV AL,0 ;код открытия для чтения
LEA DX,FILEPATH ;DS:DX указывают на путь к файлу
INT 21H ;открываем файл
JC OPEN_ERROR ;проверка на ошибку
MOV HANDLE,AX ;запоминаем номер файла
;---вычисляем позицию записи и устанавливаем файловый указатель
MOV AX,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,3FH ;номер функции
MOV BX,HANDLE ;номер файла
MOV CX,30 ;размер записи
LEA DX,REC_BUFFER ;DS:DX указывают на буфер для записи
INT 21H ;читаем запись
JC READ_ERROR ;обработка ошибки
;---позднее, закрываем файл
MOV BX,HANDLE ;номер файла
MOV AH,3EH ;функция закрытия файла
INT 21H ;закрываем файл
JC CLOSE_ERROR ;проверка на ошибку