__________________________________________________________________________
page 60,132
TITLE HANREAD (EXE) Чтение записей, созданных в HANCREAT
; -----------------------------------------------------
STACKSG SEGMENT PARA STACK 'Stack'
DW 80 DUP(?)
STACKSG ENDS
; -----------------------------------------------------
DATASG SEGMENT PARA 'Data'
ENDCDE DB 00
HANDLE DW ?
IOAREA DB 32 DUP(' ')
PATHNAM DB 'D:\NAMEFILE.SRT',0
OPENMSG DB '*** Open error ***', 0DH, 0AH
READMSG DB '*** Read error ***', 0DH, 0AH
ROW DB 00
DATASG ENDS
; ------------------------------------------------------
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATASG
MOV DS,AX
MOV ES,AX
MOV AX,0600H
CALL Q10SCR ;Очистить экран
CALL Q20CURS ;Установить курсор
CALL E100PEN ;Открыть файл,
; ; установить DTA
CMP ENDCDE,00 ;Ошибка открытия?
JNZ A90 ; да - завершить программу
A20LOOP:
CALL F10READ ;Чтение записи с диска
CMP ENDCDE,00 ;Ошибка чтения?
JNZ A90 ; да - выйти,
CALL G10DISP ; нет - выдать имя,
JMP A20LOOP ; и продолжить
A90: RET
BEGIN ENDP
; Открытие файла:
; --------------
E100PEN PROC NEAR
MOV AH,3DH ;Функция открытия
MOV CX,00 ;Нормальные атрибуты
LEA DX,PATHNAM
INT 21H
JC E20 ;Ошибка открытия?
MOV HANDLE,AX ; нет - сохранить
RET ; файловый номер
E20:
MOV ENDCDE,01 ; да - выдать
LEA DX,OPENMSG ; сообщение об ошибке
CALL X10ERR
RET
E100PEN ENDP
; Чтение дисковой записи:
; ----------------------
F10READ PROC NEAR
MOV AX,3FH ;Функция чтения
MOV BX,HANDLE
MOV CX,32 ;30 для имени, 2 для CR/LF
LEA DX,IOAREA
INT 21H
JC F20 ;Ошибка при чтении?
CMP AX,00 ;Конец файла?
JE F30
CMP IOAREA,1AH ;Маркер конца файла (EOF)?
JE F30 ; да - выйти
RET
F20:
LEA DX,READMSG ; нет - выдать
CALL X10ERR ; сообщение об ошибке
F30:
MOV ENDCDE,01 ;Код завершения
F90: RET
F10READ ENDP
; Вывод имени на экран:
; --------------------
G10DISP PROC NEAR
MOV AH,40H ;Функция вывода на экран
MOV BX,01 ;Установить номер
MOV CX,32 ; и длину
LEA DX,IOAREA
INT 21H
CMP ROW,20 ;Последняя строка экрана?
JEA G90 ; да - обойти
INC ROW
RET
G90:
MOV AX,0601H
CALL Q10SCR ;Прокрутка (скроллинг)
CALL Q20CURS ;Установить курсор
RET
G10DISP ENDP
; Прокрутка (скроллинг) экрана:
; ----------------------------
Q10SCR PROC NEAR ;в AX - адрес элемента
MOV BH,1EH ;Установить цвет
MOV CX,0000
MOV DXX,184FH ;Функция прокрутки
INT 10H
RET
Q10SCR ENDP
; Установка курсора:
; -----------------
Q20CURS PROC NEAR
MOV AH,02 ;Функция установки курсора
MOV BH,00 ; курсор
MOV DH,ROW ; строка
MOV DL,00 ; столбец
INT 10H
RET
Q20CURS ENDP
; Вывод сообщения об ошибке:
; -------------------------
X10ERR PROC NEAR
MOV AH,40H ;в DX - адрес сообщения
MOV BX,01 ;Номер
MOV CX,20 ;Длина сообщения
INT 21H
RET
X10ERR ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.17.3. Использование файлового номера для чтения файла.
На рис.17.3 приведена программа, которая читает файл, созданный
предыдущей программой (см.рис.17.2) и отсортированный командой DOS SORT.
Для открытия файла используется функция шест.3D. Полученный в результате
файловый номер заносится в поле HANDLE и используется затем в функции
шест.3F для чтения файла.
В программе нет необходимости переносить курсор на новую строку, так
как записи содержат в конце символы "возврат каретки" и "новая строка".
ASCII-ФАЙЛЫ (ФАЙЛЫ В ФОРМАТЕ ASCII)
________________________________________________________________
В предыдущих примерах были показаны операции создания и чтения
файлов. Аналогичным образом можно обрабатывать ASCII-файлы (текстовые
файлы), созданные DOS или редактором. Для этого необходимо знать
организацию оглавления и таблицы FAT, а также способ записи данных в
сектор диска, используемый системой. Система DOS записывает, например,
ASM-файл в точном соответствии с вводом с клавиатуры, включая символы
табуляции (шест.09), возврат каретки (шест.OD) и конец строки (шест.OA).
Для экономии дисковой памяти DOS не записывает пробелы, которые находятся
на экране и предшествуют символу табуляции, и пробелы, находящиеся в
строке справа от символа "возврат каретки". Следующий пример иллюстрирует
ассемблерную команду, как она может выглядеть на экране:
MOVAH,09
Для такой строки содержимое ASCII-файла будет:
094D4F560941482C30390D0A
Когда программа TYPE или редактор читают файл и выводят на экран
символы "табуляция", "возврат каретки" и "конец строки" автоматически
выравнивают данные.
Рассмотрим программу, приведенную на рис.17.4, которая читает и
выводит на экран файл HANREAD.ASM (пример на рис. 17.3) по секторам. Если
программа HANREAD уже введена и проверена, то можно просто скопировать ее
в файл с новым именем.
__________________________________________________________________________
page 60,132
TITLE ASCREAD (COM) Чтение ASCII файла
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG
ORG 100H
BEGIN: JMP MAIN
; -------------------------------------------------
SECTOR DB 512 DUP(' ') ;Область ввода
DISAREA DB 120 DUP(' ') ;Область вывода на экран
ENDCDE DW 00
HANDLE DW 0
OPENMSG DB '*** Open error ***'
PATHNAM DB 'D:\HANREAD.ASM', 0
ROW DB 00
; -------------------------------------------------
MAIN PROC NEAR ;Основная программа
MOV AX,0600H
CALL Q10SCR ;Очистить экран
CALL Q20CURS ;Установить курсор
CALL E10OPEN ;Открыть файл,
; установить DTA
CMP ENDCDE,00 ;Ошибка при открытии?
JNE A90 ; да - выйти,
A20LOOP: ; нет - продолжить
CALL R10READ ;Чтение первого сектора
CMP ENDCDE,00 ;Конец файла, нет данных?
JE A90 ; да - выйти
CALL G10XPER ;Выдать на экран
A90: RET ;Завершить программу
MAIN ENDP
; Открыть файл на диске:
; ---------------------
E10OPEN PROC NEAR
MOV AH,3DH ;Функция открытия
MOV AL,00 ;Только чтение
LEA DX,PATHNAM
INT 21H
JNC E20 ;Проверить флаг CF
CALL X10ERR ; ошибка, если установлен
RET
E20:
MOV HANDLE,AX ;Запомнить номер файла
RET
E10OPEN ENDP
; Построчный вывод данных на экран:
; --------------------------------
G10XPER PROC NEAR
CLD ;Направление слева-направо
LEA SI,SECTOR
G20:
LEA DI,DISAREA
G30:
LEA DX,SECTOR+512
CMP SI,DX ;Конец сектора?
JNE G40 ; нет - обойти,
CALL R10READ ; да - читать следующий
CMP ENDCDE,00 ;Конец файла?
JE G80 ; да - выйти
LEA SI,SECTOR
G40:
LEA DX,DISAREA+80
CMP DI,DX ;Конец DISAREA?
JB G50 ; нет - обойти,
MOV [DI],0D0AH ; да - установить CR/LF
CALL H10DISP ; и выдать на экран
LEA DI,DISAREA
G50:
LODSB ;Загрузить [SI] в AL
; и увеличить SI
STOSB ;Записать AL в [DI]
; и увеличить DI
CMP AL,1AH ;Конец файла?
JE G80 ; да - выйти
CMP AL,0AH ;Конец строки?
JNE G30 ; нет - повторить цикл,
CALL H10DISP ; да - вывести на экран
JMP G20
G80:
CALL H10DISP ;Вывести последнюю строку
G90: RET
G10XPER ENDP
; Вывод строки на экран:
; ---------------------
H10DISP PROC NEAR
MOV AH,40H ;Функция вывода на экран
MOV BX,01 ;Номер (Handle)
LEA CX,DISAREA ;Вычислить
NEG CX ; длину
ADD CX,DI ; строки
LEA DX,DISAREA
INT 21H
CMP ROW,22 ;Последняя строка экрана?
JAE H20 ; нет - выйти
INC ROW
JMP H90
H20:
MOV AX,0601H ;Прокрутка (скроллинг)
CALL Q10SCR
CALL Q20CURS
H90: RET
H10DISP ENDP
; Чтение дискового сектора:
; ------------------------
R10READ PROC NEAR
MOV AH,3FH ;Функция чтения
MOV BX,HANDLE ;Устройство
MOV CX,512 ;Длина
LEA DX,SECTOR ;Буфер
INT 21H
MOV ENDCDE,AX
RET
R10READ ENDP
; Прокрутка (скроллинг) экрана:
; ----------------------------
Q10SCR PROC NEAR ;в AX адрес элемента
MOV BH,1EH ;Установить цвет
MOV CX,0000 ;Прокрутка
MOV DX,184FH
INT 10H
RET
Q10SCR ENDP
; Установка курсора:
; -----------------
Q20CURS PROC NEAR
MOV AH,02 ;Функция
MOV BH,00 ; установки курсора
MOV DH,ROW
MOV DL,00
INT 10H
RET
Q20CURS ENDP
; Вывод сообщения об ошибке на диске:
; ----------------------------------
X10ERR PROC NEAR
MOV AH,40H ;Функция вывода на экран
MOV BX,01 ;Номер устройства
MOV CX,18 ;Длина
LEA DX,OPENMSG
INT 21H
MOV ENDCDE,O1 ;Индикатор ошибки
RET
X10ERR ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.17.4. Чтение ASCII-файла.