Справочник программиста на персональном компьютере фирмы 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     ;проверка на ошибку