На этом шаге мы приведем пример программы, использующей блочное чтение и запись.
Приведенный пример программы создает файл на диске, состоящие не более чем из 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
На следующем шаге рассмотрим абсолютные операции дискового ввода и вывода.