Буфер: |запись 00|запись 01|запись 02|... |запись 15|
DTA : |запись 00|
Второй операции чтения нет необходимого обращаться к диску. Так как
требуемая запись уже находится в буфере, то операция просто пересылает
запись 01 из буфера в DTA и увеличивает номер текущей записи на единицу.
Таким же образом выполняются следующие операции чтения пока все 16 записей
из буфера не будут обработаны.
Операции чтения 16-ой записи приводит к физическому чтению следующего
сектора в буфер и пересылка первой записи сектора в DTA. Последующие
операции чтения переносят остальные записи из буфера в DTA. Попытка
прочитать после последней записи вызовет состояние конца файла и в регистр
AL будет записан код возврата шест.01.
ПРЯМОЙ ДОСТУП
________________________________________________________________
До сих пор в этой главе рассматривалась последовательная обработка
дисковых файлов, которая адекватна как для создания файла, так и для
печати его содержимого или внесения изменений в небольшие файлы. Если
программа ограничена только возможностью последовательной обработки, то
для изменения файла она должна считывать каждую запись, вносить изменения
в определенные из них и заносить записи в другой файл (программа может
использовать один DTA, но потребуются различные блоки FCB). Обычной
практикой является чтение входного файла с диска A и запись обновленного
файла на диск B. Преимущество этого способа состоит в том, что он
автоматически оставляет резервную копию.
В некоторых случаях применяется доступ к конкретным записям файла для
получения информации, например, нескольких служащих или о части
ассортимента товаров. Для доступа, скажем, к 300-ой записи файла,
последовательная обработка должна включать чтение всех 299 предшествующих
записей, пока не будет получена 300-я запись. П р и м е ч а н и е: система
может начать обработку с конкретного номера блока и записи).
Несмотря на то, что файл создается последовательно, доступ к записям
может быть последовательным или прямым (произвольным). Требования прямой
обработки, использующей вызов DOS, заключаются в установке требуемого
номера записи в соответствующее поле FCB и выдаче команды прямого чтения
или записи.
Произвольный доступ использует относительный номер записи (байты
33-36) в блоке FCB. Поле имеет размер двойного слова и использует обратную
последовательность байт в словах. Для локализации требуемой записи система
автоматически преобразует относительный номер записи в номер текущего
блока (байты 12-13) и номер текущей записи (байт 32).
Пpямое чтение
---------------
Операции открытия и установки DTA одинаковы как для прямой, так и для
последовательной обработки. Предположим, что программа должна выполнить
прямой доступ к пятой записи файла. Установим значение 05 в поле FCB для
относительного номера записи и выполним команды для прямого чтения. В
результате успешной операции содержимое пятой записи будет помещено в DTA.
Для прямого чтения записи необходимо поместить требуемое значение
относительного номера записи в FCB и вызвать функцию шест.21:
MOV AH,21H ;Запрос на
LEA DX,FCBname ; прямое чтение
INT 21H ;Вызов DOS
Операция чтения преобразует относительный номер записи в номера
текущего блока и записи. Полученные значения используются для локализации
требуемой дисковой записи, передачи содержимого записи в DTA и установки в
регистр AL следующие значения:
00 Успешное завершение
01 Данные не доступны
02 Чтение прекращено из-за нехватки места в DTA
03 Прочитана частичная запись, заполненная нулями.
Как видно, среди перечисленных кодов возврата отсутствует состояние
конец файла. При корректном чтении записи предполагается единственный код
возврата - 00. Остальные коды возврата могут являться результатом
установки неправильного относительного номера записи или некорректная
установка адреса DTA или FCB. Так как такие ошибки легко допустить, то
полезно выполнять проверку регистра AL на ненулевое значение.
Когда программа выдает первый запрос на прямую запись, операция,
используя оглавление для локализации сектора, на котором находится
требуемая запись, считывает весь сектор с диска в буфер и пересылает
запись в DTA. Предположим, например, что записи имеют размер 128 байт,
т.е. четыре записи в одном секторе. Запрос на прямое чтение записи 23
приводит к чтению в буфер четырех записей, лежащих в одном секторе:
| запись 20 | запись 21 | запись 22 | запись 23 |
Когда программа вновь выдаст прямой запрос на запись, например, 23,
то операция сначала проверит содержимое буфера. Так как данная запись уже
находится в буфере, то она непосредственно пересылается в DTA. Если
программа запросит запись 35, который нет в буфере, операция через
оглавление локализует требуемую запись, считает весь сектор в буфер и
поместит запись в DTA. Таким образом, операции прямого доступа к записям
более эффективны, если номера записей близки друг к другу.
Пpямая запись
---------------
Операция создания файла и установки DTA одинаковы как для прямого,
так и для последовательного доступа. Для обработки файла учета товаров
программа может, используя прямой доступ, считать необходимую запись,
внести, введенные вручную, изменения (например, новое количество товаров)
и вернуть запись на диск на то же место. Операция прямой записи использует
относительный номер записи в блоке FCB и функцию шест.22 следующим
образом:
MOV AH,22H ;Запрос на
LEA DX,FCBname ; прямую запись
INT 21H ;Вызов DOS
Операция устанавливает в регистре AL следующие коды возврата:
00 Успешная операция
01 На диске нет места
02 Операция прекращена в результате недостаточного места в DTA.
При создании нового файла прямым доступом может быть получен
ненулевой код возврата. Но при прямом чтении и переписывании измененных
записей на том же месте диска код возврата должен быть только 00.
Относительный номер записи в блоке FCB при прямом доступе имеет
размер двойного слова (четыре байта), каждое слово записывается обратной
последовательностью байтов. Для небольших файлов возможно потребуется
установка лишь самого левого байта или слова, но для больших файлов
установка номера записи в трех или в четырех байтах требует некоторой
тщательности.
ПРОГРАММА: ПРЯМОЕ ЧТЕНИЕ ДИСКОВОГО ФАЙЛА
________________________________________________________________
page 60,132
TITLE RANREAD (COM) Прямое чтение записей,
; созданных в FCBCREAT
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG
ORG 100H
BEGIN: JMP MAIN
;-----------------------------------------------------
FCBREC LABEL BYTE ;FCB для дискового файла
FCBDRIV DB 04 ; дисковод D
FCBNAME DB 'MAMEFILE' ; имя файла
FCBEXT DB 'DAT' ; тип файла
FCBBLK DW 0000 ; номер текущего блока
FCBRCSZ DW 0000 ; длина логической записи
DD ? ; размер файла (DOS)
DW ? ; дата (DOS)
DT ? ; зарезервировано (DOS)
DB 00 ; номер текущей записи
FCBRNRC DD 000000000 ; относительный номер
RECLEN EQU 32 ;Длина записи
RECDPAR LABEL BYTE ;Список параметров:
MAXLEN DB 3 ;
ACTLEN DB ? ;
RECDNO DB 3 DUP(' ') ;
NAMEFLD DB RECLEN DUP(' '),13,10,'$' ;DTA
OPENMSG DB '*** Open error ***',13,10,'$'
READMSG DB '*** Read error ***',13,10,'$'
COL DB 00
PROMPT DB 'Record number? $'
ROW DB 00
ENDCDE DB 00
;-----------------------------------------------------
MAIN PROC NEAR
CALL Q10CLR ;Очистить экран
CALL Q20CURS ;Установить курсор
CALL C10OPEN ;Открыть файл,
; установить DTA
CMP ENDCDE,00 ;Открытие без ошибок?
JZ A20LOOP ; да - продолжить,
RET ; нет - завершить
A20LOOP:
CALL D10RECN ;Получить номер записи
CMP ACTLEN,00 ;Есть запрос?
JE A40 ; нет - выйти
CALL F10READ ;Чтение (прямой доступ)
CMP ENDCDE,00 ;Есть ошибки чтения?
JNZ A30 ; да - обойти
CALL G10DISP ;Вывести на экран
A30:
JMP A20LOOP
A40: RET ;Завершить программу
MAIN ENDP
; Подпрограмма открытия файла на диске:
; ------------------------------------
C10OPEN PROC NEAR
MOV AH,0FH ;Функция открытия
LEA DX,FCBREC
INT 21H
CMP AL,00 ;Открытие нормальное?
JNZ C20 ; нет - ошибка
MOV FCBRCSZ,RECLEN ;Длина записи (EQU)
MOV AH,1AH
LEA DX,NAMEFLD ;Установить адрес DTA
INT 21H
RET
C20:
LEA DX,OPENMSG
CALL X10ERR
RET
C10OPEN ENDP
; Ввод с клавиатуры номера записи:
; -------------------------------
D10RECN PROC NEAR
MOV AH,09H ;Функция вывода на экран
LEA DX,PROMPT
INT 21H
MOV AH,0AH ;Функция ввода с клавиатуры
LEA DX,RECDPAR
INT 21H
CMP ACTLEN,01 ;Проверить длину (0,1,2)
JB D40 ;Длина 0, завершить
JA D20
SUB AH,AH ;Длина 1
MOV AL,RECDNO
JMP D30
D20:
MOV AH,RECDNO ;Длина 2
MOV AL,RECDNO+1
D30:
AND AX,0F0FH ;Удалить ASCII тройки
AAD ;Преобразовать в двоичное
MOV WORD PTR FCBRNRC,AX
D40:
MOV COL,20
CALL Q20CURS ;Установить курсор
RET
D10RECN ENDP
; Чтение дисковой записи:
; ----------------------
F10READ PROC NEAR
MOV ENDCDE,00 ;Очистить код завершения
MOV AH,21H ;Функция прямого чтения
LEA DX,FCBREC
INT 21H
CMP AL,00 ;Чтение без ошибок?
JZ F20 ; да - выйти
LEA DX,READMSG ; нет - выдать
CALL X10ERR ; сообщение об ошибке
F20: RET
F10READ ENDP
; Вывод имени на экран:
; --------------------
G10DISP PROC NEAR
MOV AH,09 ;Функция вывода на экран
LEA DX,NAMEFLD
INC 21H
INC ROW
MOV COL,00
RET
G10DISP ENDP
; Очистка экрана:
; --------------
Q10CLR PROC NEAR
MOV AX,0600H ;Функция прокрутки
MOV BH,41H ;Цвет (07 для ч/б)
MOV CX,0000
MOV DX,184FH
INT 10H
RET
Q10CLR ENDP
; Установка курсора:
; -----------------
Q20CURS PROC NEAR
MOV AH,02 ;Функция установки