Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29214
Скачиваний: 1689
Глава 8. Учимся работать с файлами
77
int 21h
...
File_name db 'command.com',0
...
Обратите внимание, что в регистр
ax
загружаются сразу два числа:
3Dh
и
02h
.
Такой метод работает быстрее и занимает меньше байтов, чем если бы мы загру-
жали оба числа по отдельности:
...
mov ah,3Dh
mov al,02h
...
Строку
File_name db 'command.com',0
можно размещать в любом месте кода,
но только не смешивая непосредственно с кодом. Например, нельзя вставлять дан-
ные между операторами ассемблера:
...
mov ax,3D02h
mov dx,offset File_name
File_name db 'command.com',0
int 21h
...
Обратите внимание, что между командами
mov dx,offset File_name
и
File_name db
'
command.com
' не стоит многоточие. В данном случае, программа сас-
семблируется без ошибок, но зависнет при запуске. Процессор распознает
'command.com'
как набор инструкций, а не строку символов. Эти инструкции, ско-
рее всего, не имеют никакой логики (рис. 8.1). После команды
mov dx,0106h
(
mov
dx,offset File_name
) мы видим шестнадцатеричный код строки
File_name
—
"command.com"
. Как только процессор загрузит в
dx
адрес этой строки, он начнет
выполнять следующую за ней команду
aprl
, затем
insw
и т. д., что, безусловно,
приведет к "зависанию" компьютера.
Из этого делаем вывод, что процессор "не отличает" данные от кода. Он просто
выполняет последовательность байт, которые ему указал программист. Поэтому на
плечи программиста ложится задача отслеживать, чтобы данные не попали в об-
ласть кода, и процессор не начал их выполнять.
Вернемся к функциям работы с файлами. При открытии файла можно указывать
не только его имя, но и полный путь к нему:
File_name db 'C:\ASSM\command.com',0
Если имя диска или путь к нему опущены, то операционная система будет пы-
таться открыть файл на текущем диске в текущем каталоге. Если же указан полный
путь, то файл-система попытается открыть файл только по указанному пути.
ПРОПИСНЫЕ и строчные символы значения не имеют. Можно записать и так:
My_file db 'a:myfile.doc',0
Часть II. Усложняем задачи
78
Рис. 8.1. Недопустимость перемешивания данных с кодом
В данном случае ОС попытается открыть файл myfile.doc, который должен быть
расположен на диске A: в текущем каталоге.
Теперь о том, что возвращает функция. Вот код:
...
mov ax,3D00h
mov dx,offset Just_file
int 21h
...
Just_file db 'file',0
...
Допустим, в текущем каталоге файл с именем file (см. последнюю строку в при-
веденном выше примере) не был найден. Тогда функция
3Dh
устанавливает в еди-
ницу флаг переноса (вспомните схожую ситуацию с флагом нуля). Если же файл
все-таки найден и успешно открыт, то флаг переноса сбрасывается (становится
равным нулю).
Для проверки состояния флага переноса используются операторы
jc
(от англ.
jump if carry — переход, если установлен флаг переноса) и
jnc
(от англ. jump if not
carry — переход, если флаг переноса не установлен):
...
int 21h
jc Error
Ok:
...
Error:
...
Глава 8. Учимся работать с файлами
79
или так:
...
int 21h
jnc Ok
Error:
...
Ok:
...
Естественно, вместо меток
Ok
(порядок) и
Error
(ошибка) можно задавать лю-
бые другие имена. По аналогии с
je
и
jne
, можно сделать вывод, что
jc
и
jnc
—
команды условного перехода.
Все функции прерывания
21h
устанавливают в единицу флаг переноса, если
произошла ошибка, и сбрасывают его, если ошибки не было. Однако ошибка при
попытке открыть файл может возникать и в следующих случаях:
файл не найден. Имя файла или путь к нему не найдены;
файл уже открыт какой-то программой. Файл не может быть одновременно от-
крыт двумя и более программами (процессами);
открыто максимально возможное количество файлов. Максимальное количество
одновременно открытых файлов указывается в переменной
FILES=XX
файла
config.sys, где
XX
— число не более 99. MS-DOS резервирует для каждого файла
определенное количество байтов памяти;
попытка открыть файл с атрибутом "только чтение" для чтения и/или записи.
Прежде необходимо снять этот атрибут, а затем уже открывать файл для чте-
ния/записи.
В листинге 8.3 приведен код, который открывает файл и выводит сообщение
о том, открыт файл или нет.
Листинг 8.3. Открытие файла
...
mov ax,3D00h
mov dx,offset File_name
int 21h
jc Bad_file
mov dx,offset Mess1
Quit_prog:
mov ah,9
int 21h
int 20h
Bad_file:
mov dx,offset Mess2
Часть II. Усложняем задачи
80
jmp Quit_prog
...
File_name db 'c:\assm\masm\binr\ml.exe',0
Mess1 db 'Файл успешно открыт!$'
Mess2 db 'Не удалось открыть файл!$'
...
Рис. 8.2. Успешное открытие файла
При успешном открытии файла в
ax
возвращается уникальный идентификаци-
онный номер файла. В дальнейшем, при обращении к данному файлу, будет указы-
ваться не его имя, а этот номер. Флаг переноса сброшен. После вызова функции
3Dh
необходимо сохранить номер файла, переданный ею в регистре
ax
! Состояние
регистров после открытия файла в отладчике отображено на рис. 8.2.
После того как программист закончил работу с файлом (записал или прочитал
что-нибудь), файл необходимо закрыть функцией
3Eh
прерывания
21h
(табл. 8.2).
Таблица 8.2. Функция
3Eh
прерывания
21h
— закрытие файла
Вход
Выход
ah = 3Eh
bx
= номер файла
Ничего
Все данные, которые мы записывали в файл, на самом деле не записываются
в тот же момент на диск. Они хранятся в памяти до тех пор, пока файл не будет за-
крыт. Только после этого сбрасываются все дисковые буферы, и файл сохраняется
на диске.
Глава 8. Учимся работать с файлами
81
Не забывайте закрывать файл! В любом случае, при завершении работы про-
граммы, операционная система автоматически закрывает все открытые этой про-
граммой файлы, освобождает занимаемую ею память и отведенные ей блоки памяти,
а также сбрасывает дисковые буферы (т. е. происходит запись данных, оставшихся
в кэш-памяти, на диск). Далее приведен участок кода, закрывающий открытый
файл, номер которого находится в переменной
Handle
:
...
mov ah,3Eh
mov bx,Handle
int 21h ;Файл закрыт
...
Обратите внимание на запись
mov bx,Handle
. Здесь
Handle
— это переменная,
в которую необходимо будет занести номер файла после открытия. Переменные
мы подробно рассмотрим в следующих главах, а сейчас коснемся только того, как
создать переменную
Handle
. Вот пример:
Handle dw 0
Здесь мы резервируем два байта для хранения некоторых данных. В нашем слу-
чае — для хранения номера файла. В листинге 8.4 приведен фрагмент программы,
который открывает файл для чтения, сохраняет номер файла в переменной, а затем
закрывает файл.
Листинг 8.4. Корректное открытие и закрытие файла
...
mov ax,3D00h
mov dx,offset File_name
int 21h
jc Error
mov Handle,ax
;файл открыт успешно...
mov ah,3Eh
mov bx, Handle
int 21h
;файл закрыт
Error:
int 20h
...
Handle dw 0
...
Для чтения информации из файла используется функция
3Fh
, а для записи
в файл —
40h
. При этом
bx
должен содержать тот самый номер файла —
Handle
,