Страница 39 из 41
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 ;проверка на ошибку
|