На этом шаге мы приведем пример программы, использующей блочное чтение и запись.
Приведенный пример программы создает файл на диске, состоящие не более чем из 100 целых чисел (0 - признак выхода из процедуры ввода). Все числа помещаются в область DTA, содержимое которой помещается на диск перед завершением процедуры выхода.
Перед чтением из файла указывется номер элемента, с которого нужно начать вывод элементов файла. После уменьшения этого значения на 1 (нумерация элементов в файле начинается с 0!) полученное значение помещается в поле относительного номера записи, так как именно оно отвечает за задание начального номера записи, с которого начинается блочное чтение.
Прочитанные элементы помещаются в область DTA, откуда в цикле они выводятся на экран (количество реально прочитанных записей помещается именно в этот регистр).
TITLE Прямой блочный доступ в базовой версии DOS.
;Программа сделана как EXE-файл.
;-------------------------------
EXTRN Vvod:FAR,Vyvod:FAR,Clear:FAR,Write_Str:FAR,Cursor:FAR
;----- Сегмент стека
StackSg SEGMENT PARA STACK 'Stack'
DW 256 DUP(?)
StackSg ENDS
;----- Сегмент данных
DataSg SEGMENT PARA PUBLIC
;-------- Блок FCB
FILE LABEL BYTE ;Список параметров.
FCBDRV DB 05 ;Диск E (При необходимости - измените!!!).
FCBNAME DB 'PROBA ' ;Имя файла, дополненное
;тремя пробелами.
FCBEXT DB 'DAT' ;Расширение.
FCBBLK DW 0000 ;Номер текущего блока.
FCBRCSZ DW ? ;Размер логической записи.
DD ? ;Размер файла (DOS).
DW ? ;Дата (DOS).
DT ? ;Зарезервировано (DOS).
FCBSQRC DB 00 ;Номер текущей записи.
FCBOTRC DD 00000000 ;Относительный номер.
DTA DW 200 DUP (?) ;Область DTA.
KOL DW ? ;Количество элементов в файле.
PUNKT DB ? ;Номер выбранного пункта меню.
STR1 DB "На диске нет свободного пространства. Программа завершена.$"
STR2 DB "Задайте целое число (0 - признак конца ввода): $"
STR3 DB "Элементы файла: $"
STR4 DB "Номер элемента, с которого осуществлять вывод содержимого файла: $"
;------- Главное меню (длина каждого элемента - 48 символов).
ELEM1 DB " Г Л А В Н О Е М Е Н Ю : $"
ELEM2 DB " Создание файла ............................. 1$"
ELEM3 DB " Просмотр файла ............................. 2$"
ELEM6 DB " Выход ...................................... 0$"
ELEM7 DB " Укажите номер пункта ....................... $"
KOLP DW 5 ;Количество пунктов меню.
DLINA DW 48 ;Длина пункта меню.
RAB1 DW ? ;Рабочая ячейка.
RAB2 DW ? ;Рабочая ячейка.
DataSg ENDS
;----- Сегмент кода
CodeSg SEGMENT PARA PUBLIC
ASSUME CS: CodeSg, DS:DataSg, SS: StackSg
Begin PROC FAR
;Пролог EXE-файла.
PUSH DS
XOR AX,AX
PUSH AX
MOV AX,DataSg
MOV DS,AX
;Конец пролога.
;---------------- Установка области DTA.
MOV AH,1AH ; Установка адреса
LEA DX,DTA ; DTA.
INT 21H ; Вызов DOS-прерывания.
@N: ;---------------- Главное меню.
CALL Menu ; Вывод меню.
CMP PUNKT,0
JE @ET ; Выход из программы.
CMP PUNKT,1
JE @P1 ; Создание файла.
CMP PUNKT,2
JE @P2 ; Просмотр файла.
JMP @N
@P1: ;---------------Создание файла.
CALL Clear ; Очистка экрана.
MOV AH,16H ; Создание
LEA DX,FILE ; дискового файла.
INT 21H ; Вызов DOS-прерывания.
CMP AL,0FFH ; Проверка на наличие свободного пространства.
JNE @PR ; Не равно - продолжаем.
MOV DX,0000h
CALL Cursor ; Установка курсора.
LEA DX,STR1
CALL Write_Str ; Вывод строки.
RET ; Конец программы.
@PR:
MOV FCBRCSZ,2 ; Установка длины записи (2 байта).
CALL Zapoln ; Обращение к процедуре заполнения файла.
JMP @N ; Переход на меню.
@P2: ;---------------Вывод содержимого файла.
CALL Vyvod_File ; Обращение к процедуре вывода содержимого файла.
MOV AH,1 ; Задержка.
INT 21H
JMP @N ; Переход на меню.
@ET: ;-------------- Выход из программы.
MOV AH,10H ; Закрыть
LEA DX,FILE ; файл.
INT 21H ; Вызов DOS-прерывания.
RET
Begin ENDP
;========== ПРОЦЕДУРА ЗАПОЛНЕНИЯ ФАЙЛА ==============
Zapoln PROC
PUSH SI
MOV KOL,0 ; Обнуление количества элементов.
MOV SI,0 ; Индекс (номер) элемента.
@START:
CALL Clear ; Очистка экрана.
MOV DX,0000h
CALL Cursor ; Установка курсора.
LEA DX,STR2
CALL Write_Str ; Вывод строки-приглашения.
CALL Vvod ; Ввод числа.
CMP BX,0 ; Проверка на выход.
JE @EXIT
MOV DTA[SI],BX ; Размещение числа в DTA.
ADD SI,2 ; Новое значение индекса.
INC KOL ; Количество элементов увеличиваем на 1.
JMP @START
@EXIT: ; Выход
MOV AH,28H ; Блочная запись.
MOV CX,KOL ; Количество элементов.
LEA DX,FILE ;
INT 21H ; Вызов DOS-прерывания.
POP SI
RET
Zapoln ENDP
;========== ПРОЦЕДУРА ВЫВОДА СОДЕРЖИМОГО ФАЙЛА ==============
Vyvod_File PROC
CALL Clear ; Очистка экрана.
MOV DX,0000h
CALL Cursor ; Установка курсора.
LEA DX,STR4
CALL Write_Str ; Вывод строки.
CALL Vvod
DEC BX ; Вычисление начального номера элемента для вывода.
MOV DX,0100h
CALL Cursor ; Установка курсора.
LEA DX,STR3
CALL Write_Str ; Вывод строки.
; Перемещение указателя на начальный элемент:
MOV WORD PTR FCBBLK,0 ; - обнуление номера текущего блока;
MOV WORD PTR FCBSQRC,0 ; - обнуление начального номера записи;
MOV WORD PTR FCBOTRC,BX ; - установка относительного номера записи.
MOV AH,27H ; Блочное чтение.
MOV CX,KOL ; Количество записей
SUB CX,BX ; для чтения.
LEA DX,FILE ;
INT 21H ; Вызов DOS-прерывания.
CMP AL,0 ; Все нормально?
JNE @EXT; ; Нет - выход.
MOV SI,0
@PROD:
MOV BX,DTA[SI] ; Размещение прочитанного в BX.
CALL Vyvod ; Вывод на экран
MOV AH,2
MOV DL,' ' ; Вывод пробела (разделителя между числами).
INT 21H
ADD SI,2
LOOP @PROD
@EXT: ; Выход.
RET
Vyvod_File ENDP
;========== ГЛАВНОЕ МЕНЮ ==============
Menu PROC
PUSH CX
PUSH DX
CALL Clear ; Очистка экрана.
MOV DX,0000 ; Начальная позиция курсора.
MOV RAB1,DX ; Сохраним значение DX (позицию курсора).
LEA DX,ELEM1 ; Адрес первого пункта меню.
MOV CX,KOLP ; Количество пунктов меню.
MOV RAB2,DX ; Сохраним значение DX (адрес начала меню).
@POWT:
MOV DX,RAB1 ; Восстановим сохраненную позицию курсора.
CALL Cursor ; Установка курсора.
INC DH ; Увеличим номер строки.
MOV RAB1,DX ; Сохраним значение DX (позицию курсора).
MOV DX,RAB2 ; Восстановим сохраненный адрес начала меню.
CALL Write_Str ; Вывод пункта меню.
ADD DX,DLINA ; Получм адрес следующего пункта меню.
MOV RAB2,DX ; Сохраним значение DX (адрес пункта меню).
LOOP @POWT
MOV AH,1
INT 21H
SUB AL,30H
MOV PUNKT,AL ; Сохраняем номер выбранного пункта.
POP DX
POP CX
RET
Menu ENDP
CodeSg ENDS
END Begin
На следующем шаге рассмотрим абсолютные операции дискового ввода и вывода.