f20: ret f10writ endp
;Закрытие дискового файла:
g10clse |
proc near |
|
mov |
namedta,1ah |
;установить конец файла EOF |
call |
f10writ |
|
mov |
ah,10h |
;функция закрытия |
lea |
dx,fcbrec |
|
int |
21h |
|
ret |
|
|
g10clse |
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 |
dl,00 |
|
mov |
dh,row |
;установить курсор |
int |
10h |
|
ret |
|
|
q20curs |
endp |
|
;Вывод сообщения об ошибке на диске:
x10err |
proc near |
|
mov |
ah,09 |
;dx содержит |
int |
21h |
; адрес сообщения |
mov |
errcde,01 |
;установить код ошибки |
ret |
|
|
x10err |
endp |
|
codesg |
ends |
|
end |
begin |
|
__________________________________________________________________________
Программа, приведенная в данном примере, создает дисковый файл по имени, которое вводится пользователем с клавиатуры. Блок FCB (fcbrec) в данной программе содержит следующие поля:
fcbdriv программа должна создать файл на диске 4 (или D). fcbname имя файла namefile.
fcbext тип файла dat.
fcbblk Начальное значение номера текущего блока 0.
fcbrcsz Размер записей не определен, так как операция открытия устанавливает в данном поле значение 128.
fcbsqrc -начальное значение номера текущей записи 0.
66
В программе организованы следующие процедуры:
begin вызывает c10open для создания файла и установки адреса DTA для DOS, вызывает d10proc для ввода имени файла. Если ввод пустой, то происходит вызов g10clse для завершения программы;
c10open создает для файла элемент в директории, устанавливает размер записей 32 (шест.20) и инициализирует адрес буфера DTA для DOS. d10proc выдает запрос на ввод имен, вводит имена с клавиатуры и
вызывает процедуру f10writ для записи вводимых имен на диск. e10dispуправляет прокруткой и установкой курсора. f10writ записывает имена в дисковой файл.
g10clse записывает маркер конца файла и закрывает файл.
x10err выдает на экран сообщение об ошибке в случае некорректной операции создания файла или записи данных.
Каждая операция записи автоматически добавляет 1 к fcbsqrc (номер текущей записи) и шест. 20 (размер записи) к fcbflsz (размер файла). Так как каждая запись имеет длину 32 байта, то операция заносит в буфер 16 записей и затем записывает весь буфер в сектор диска. Ниже показано содержимое DTA и буфера:
DTA: |текущая запись|
Буфер: |запись 00|запись 01|запись 02|...|запись 15| Если пользователь ввел 25 имен, то счетчик записей увеличится от 1 до 25
(шест.19). Размер файла составит:
25 * 32 байта = 800 байтов или шест. 320 Операция закрытия заносит во второй сектор оставшиеся в буфере девять
записей и изменяет в оглавлении дату и размер файла. Размер записывается байтами в переставленном порядке: 20030000. Последний буфер имеет следующий вид:
Буфер: |запись 16|запись 17|...|запись 24|шест.1A|...|...|
Для простоты в приведенной программе создаются записи файла, содержащие только одно поле. Записи большинства других файлов, однако, содержат различные символьные и двоичные поля и требуют описания записи в DTA. Если записи содержат двоичные числа, то не следует использовать маркер конца файла (EOF), так как двоичное число может совпасть с шест. кодом 1A.
Для того, чтобы сделать программу более гибкой, можно разрешить пользователю указать дисковод, на котором находится или будет находиться файл. В начале выполнения программа может выдать на экран сообщение, чтобы пользователь ввел номер дисковода, а затем изменить первый байт блока
FCB.
=================================================================
Пример П.1.5
; lab3pr5.asm программа, использующая FCB для чтения дискового файла
;Чтение записей созданных в CREATDSK
;-------------------------------------------------------
codesg segmentPARA 'Code'
assume cs:codesg,ds:codesg,ss:codesg,es:codesg
org |
100h |
; обход PSP |
begin: jmp |
main |
;обход через данные |
|
|
67 |
; --------------------------------------------------- |
|
|||
fcbrec label |
byte |
|
;FCB для файла |
|
fcbdriv |
db |
04 |
; дисковод D |
|
fcbname |
db |
'namefile' |
; имя файла |
|
fcbext |
|
db |
'dat' |
; тип файла |
fcbblk |
|
dw |
0000 |
; номер текущего блока |
fcbrcsz |
dw |
0000 |
; длина логической записи |
|
fcbflsz |
|
dd |
? |
; размер файла (DOS) |
|
|
dw |
? |
; дата (DOS) |
|
|
dt |
? |
; зарезервировано (DOS) |
fcbsqrc |
db |
00 |
; текущий номер записи |
|
|
|
dd |
? |
; относительный номер |
reclen |
|
equ |
32 |
;длина записи |
namefld |
db |
reclen dup(' '), 13, 10, '$' |
||
endcde |
db |
00 |
|
|
openmsg |
db |
'*** Open error ***', '$' |
||
readmsg |
db |
'*** Read error ***', '$' |
||
row |
db |
00 |
|
|
main |
proc |
far |
|
|
|
mov |
ax,0600h |
|
|
|
call |
q10scr |
|
;очистить экран |
|
call |
q20curs |
;установить курсор |
|
|
call |
e10open |
;открыть файл и установить DTA |
|
|
cmp |
endcde,00 |
;открытие без ошибок? |
|
|
jnz |
a90 |
; |
нет завершить |
a20loop: |
|
|
|
|
|
call |
f10read |
;прочитать запись |
|
|
cmp |
endcde,00 |
;чтение без ошибок? |
|
|
jnz |
a90 |
; |
нет выйти |
|
call |
g10disp |
;выдать имя на экран |
|
|
jmp |
a20loop |
;продолжить |
|
a90: |
ret |
|
|
;завершить |
begin |
endp |
|
|
|
;Открытие файла на диске:
e10open |
proc near |
|
lea |
dx,fcbrec |
|
mov |
ah,0fh |
;функция открытия |
int |
21h |
|
cmp |
al,00 |
;файл найден? |
jnz |
e20 |
; нет ошибка |
mov |
fcbrcsz,reclen |
;длина записи (EQU) |
mov |
ah,1ah |
|
lea |
dx,namefld |
;адрес DTA |
int |
21h |
|
ret |
|
|
e20: |
|
|
mov |
endcde,01 |
;сообщение об ошибке |
lea |
dx,openmsg |
|
call |
x10error |
|
|
|
68 |
ret e10open endp
;Чтение дисковой записи:
f10read |
proc near |
|
|
mov |
ah,14h |
;функция чтения |
|
lea |
dx,fcbrec |
|
|
int |
21h |
|
|
cmp |
namefld,1ah |
;считан маркер EOF? |
|
jne |
f20 |
; |
нет |
mov |
endcde,01 |
; |
да |
jmp |
f90 |
|
|
f20: |
|
|
|
cmp |
al,00 |
;чтение без ошибок? |
|
jz |
f90 |
; |
да выйти |
mov |
endcde,01 |
; |
нет: |
cmp |
al,01 |
;конец файла? |
|
jz |
f90 |
; |
да выйти, |
lea |
dx,readmsg |
; |
нет значит |
call |
x10err |
; ошибка чтения |
|
f90: |
|
|
|
ret |
|
|
|
f10read |
endp |
|
|
;Вывод записи на экран:
g10disp |
proc near |
|
|
mov |
ah,09 |
;функция вывода на экран |
|
lea |
dx,namefld |
|
|
int |
21h |
|
|
cmp |
row,20 |
;последняя строка экрана? |
|
jae |
g30 |
; |
нет... |
inc |
row |
; |
да увеличить строку |
jmp |
g90 |
|
|
g30: |
|
|
|
mov |
ax,0601h |
|
|
call |
q10scr |
; прокрутить |
|
call |
q20curs |
; установить курсор |
|
g90: ret |
|
|
|
g10disp |
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 |
69
mov dh,row mov dl,00 int 10h ret
q20curs endp
;Вывод сообщения об ошибке на диске:
x10err |
proc |
near |
mov |
ah,09 |
;dx содержит адрес |
int |
21h |
; сообщения |
ret |
|
|
x10err |
endp |
|
codesg |
ends |
|
end |
begin |
|
В данном примере приведена программа, которая выполняет чтение файла, созданного предыдущей программой, и вывод на экран имен из записей файла. Обе программы содержат идентичные блоки FCB, хотя имена полей FCB могут быть различны. Содержимое полей имени и типа файла должны быть одинаковы. Программа содержит следующие процедуры:
begin вызывает процедуру e10open для открытия файла и установки DTA и вызывает f10read для чтения записей. Если считан маркер конца файла, то программа завершается, если нет, то вызывается процедура g10disp.
e10open открывает файл, устанавливает значение размера и записей, равное 32 (шест. 20), и инициализирует адрес DTA.
f10read выполняет последовательное чтение записей. Операция чтения автоматически увеличивает номер текущей записи в блоке FCB.
g10disp выводит на экран содержимое прочитанной записи.
x10err выводит на экран сообщение об ошибке в случае некорректной операции открытия или чтения.
Операция открытия выполняет поиск имени и типа файла в оглавлении. Если необходимый элемент оглавления найден, то автоматически в блок FCB заносятся размер файла, дата и длина записей. Первая операция чтения записи с номером 00 получает доступ к диску и считывает весь сектор (16 записей) в буфер. После этого первая запись заносится в DTA, а номер текущей записи в FCB увеличивается с 00 до 01:
Буфер: |запись 00|запись 01|запись 02|... |запись 15| DTA : |запись 00|
Второй операции чтения нет необходимости обращаться к диску. Так как требуемая запись уже находится в буфере, то операция просто пересылает запись 01 из буфера в DTA и увеличивает номер текущей записи на единицу.
Таким же образом выполняются следующие операции чтения, пока все 16 записей из буфера не будут обработаны.
Операция чтения 16-й записи приводит к физическому чтению следующего сектора в буфер и пересылке первой записи сектора в DTA. Последующие операции чтения переносят остальные записи из буфера в DTA. Попытка прочитать после последней записи вызовет состояние конца файла и в регистр al будет записан код возврата шест. 01.
70