Функции DOS. Часть 1.
Большинство функций DOS вызываются с помощью прерывания INT 21h. (См.
"Прерывания DOS"). Перед вызовом прерывания нужно в регистр АН записать
номер функции, которую нужно выполнить. Ниже приводятся основные
функции DOS и рассмотрены некоторые примеры применения этих функций.
После слова "Вход" следует список регистров и информации, которая
должна быть записана в эти регистры перед вызовом прерывания. После
слова "Выход" следует список регистров и информация, которая будет
находиться в этих регистрах после выполнения прерывания.
Если вам не приходилось писать программы на Ассемблере, то вы наверняка
не знаете, каким образом компилируются исходные файлы. Поэтому приведу
пример создания готового приложения. Для этого будем использовать Турбо
Ассемблер (TASM). Итак, скопируйте любой из приведенных ниже примеров
в какой-нибудь простой текстовый редактор (например, в Блокнот от
Windows). Затем сохраните этот файл с расширением .asm. Пусть,
например, это будет файл MyProg.asm. После этого в командной строке наберите:
tasm myprog.asm
и нажмите Enter или щелкните по кнопке ОК. Если вы не знаете что такое
командная строка, то читайте материал
"Кое-что о DOS". Если TASM у вас
установлен не в корневом каталоге, а ваш исходный файл также находится
не в корневом каталоге (а, например, в папке PROG), то необходимо
прописывать полный путь, например:
С:\tasm\bin\tasm C:\PROG\myprog.asm
После компиляции вы увидите окно (если работаете в Windows), в котором
будут сообщения об ошибках (если таковые имеются) и прочая служебная
информация. Если ошибок не было, то будет создан объектный файл с
расширением .obj. Этот файл обычно создается в корневом каталоге или
на рабочем столе (если вы работаете в Windows). Если же его там
почему-то нет, то воспользуйтесь функцией поиска файлов, что бы
определить его местоположение. Теперь нам нужно скомпоновать этот
объектный файл в готовую программу (исполняемый файл). Все примеры,
приведенные здесь, написаны как программы типа СОМ. Поэтому приведу
здесь только способ создания именно СОМ-программы:
С:\tasm\bin\tlink /t /x myprog.obj
Как вы заметили, я не пишу полный путь для объектного файла, потому
как для файлов, которые находятся в корневом каталоге этого делать
обычно не нужно. Однако если вам будет выдано сообщение, что путь не
найден, то придется написать полный путь. Такое сообщение может быть
выдано и в том случае, если папка или файл имеют русское название или
длину более 8 символов. Если все прошло нормально, то в корневом
каталоге или на рабочем столе (или в текущей папке) будет создан файл
myprog.com - это и есть готовая программа. Можете ее запустить и
проверить. См. также
MASM, TASM и WASM
Некоторые приведенные здесь примеры программ написаны на Паскале. Все
компиляторы Паскаля более или менее совместимы. Однако ваш компилятор
может выдать сообщение об ошибке, поскольку некоторые отличия все-таки
есть. Обычно это связано с типами данных и отсутствием тех или иных
стандартных процедур. Устранить такую проблему будет несложно.
В некоторых примерах программ используются русские буквы для вывода на
экран. Это сделано только для удобства чтения текстов программ. Если
просто скопировать такой файл в текстовый редактор, то после компиляции
и запуска программы на экране вы увидите "иероглифы". Это связано с
тем, что большинство компиляторов "не понимают" русские буквы в
кодировке Windows. Эту проблему можно решить, например, используя
редактор DOS, или (для Ассемблера) вставляя в строку не буквы, а их
ASCII-коды (например: 143, 224, 168, 162, 165, 226, '$' - это будет
строка "Привет")
Функция 01h (Считать символ из STDIN с эхом, ожиданием и проверкой на Ctrl+Break)
Функция 02h (Вывести символ на STDOUT с проверкой на Ctrl+Break)
Функция 06h (Записать символ в STDOUT без проверки на Ctrl+Break)
Функция 07h (Считать символ из STDIN без эха, с ожиданием и без проверки на Ctrl+Break)
Функция 08h (Считать символ из STDIN без эха, с ожиданием и проверкой на Ctrl+Break)
Функция 09h (Записать строку в STDOUT с проверкой на Ctrl+Break)
Функция 0Аh (Считать строку символов из STDIN в буфер)
Функция 0Вh (Проверить состояние клавиатуры)
Функция 0Сh (Очистить буфер и считать символ)
Функция 0Eh (Установить текущий диск DOS)
Функция 19h (Получить текущий диск DOS)
Функция 1Bh (Получить информацию FAT (текущий диск))
Функция 1Сh (Получить информацию FAT (любой диск))
Функция 2Аh (Получить системную дату)
Функция 2Вh (Установить системную дату)
Функция 2Ch (Получить время)
Функция 2Dh (Установить время)
Функция 39h (Создать директорию)
Функция 3Аh (Удалить директорию)
Функция 3Вh (Сменить директорию)
Функция 3Ch (Создать файл)
Функция 3Dh (Открыть существующий файл)
Функция 3Eh (Закрыть файл)
Функция 3Fh (Чтение из файла или устройства)
Функция 40h (Записать в файл или устройство)
Функция 41h (Удалить файл)
Функция 47h (Определить текущую директорию)
Функция 01h (Считать символ из STDIN с эхом, ожиданием и проверкой на Ctrl+Break)
Вход: | АН | 01h |
Выход: | AL | символ, полученный из STDIN |
Эта функция считывает (ожидает) символ со стандартного входного
устройства - STDIN (например, с клавиатуры) и отображает этот символ
на стандартном выходном устройстве - STDOUT (например, на мониторе).
При считывании символа его отображение на устройстве вывода называют
"эхом". При распознавании нажатия сочетания клавиш Ctrl+Break
выполняется прерывание INT 23h.
Ввод расширенных клавиш ASCII (F1-F12, PageUp и т.п.) требует двух
обращений к этой функции. Первый вызов возвращает AL=0, второй вызов
возвращает в AL расширенный код ASCII.
Пример:
;========================================================================
;Эта программа ожидает нажатия клавиши. Если нажата клавиша Esc, то
;программа завершается, иначе проверяется расширенный код.
;Если нажата клавиша F1, то об этом выводится сообщение,
;иначе выводится сообщение, что клавиша не определена.
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV AH, 1 ;АН = 1
INT 21h ;вызываем функцию DOS 01h
CMP AL, 1Bh ;если AL = 1Bh, то была нажата клавиша Esc
JZ btnEsc ;тогда переходим к метке btnEsc
CMP AL, 0 ;иначе, если AL не равен 0, то
JNE btnTxt ;переходим к метке btnTxt
;Если AL=0, то то был введен символ
;расширенного кода ASCII, тогда
INT 21h ;снова вызываем функцию DOS 01h
CMP AL, 3Bh ;если AL = 3Bh, то была нажата клавиша F1
JZ F1Txt ;тогда переходим к метке F1Txt
JMP btnTxt ;иначе переходим к метке btnTxt
btnTxt: MOV BX, offset btn
JMP OutTxt ;переход к метке OutTxt
F1Txt: MOV BX, offset F1
OutTxt: MOV AH, 09h ;выводим сообщение о нажатой клавише
MOV DX, BX
INT 21h
btnEsc: RET ;завершение программы
F1 DB ' Клавиша F1$'
btn DB ' Клавиша не определена$'
END start
;========================================================================
Функция 02h (Вывести символ на STDOUT с проверкой на Ctrl+Break)
Вход: | АН | 02h |
DL | символ, выводимый на устройство стандартного вывода |
Выход: | Нет | --- |
Эта функция посылает символ из регистра DL на устройство стандартного
вывода. В DL можно записать как ASCII-код символа, так сам символ. В
последнем случае символ заключается в одинарные кавычки. Если при
выполнении этой функции была нажата комбинация клавиш Ctrl+Break, то
выполняется прерывание INT 23h, которое по умолчанию осуществляет
выход из программы.
Данная функция обрабатывает некоторые управляющие символы:
Выводимый символ | Действие |
BEL (07h) | появляется звуковой сигнал |
BS (08h) | курсор перемещается на одну позицию влево |
НТ (09h) | используется для замены на несколько пробелов |
LF (0Ah) | перевод курсора на одну позицию вниз |
CR (0Dh) | переход на начало текущей строки |
Пример:
;========================================================================
;Эта программа выводит на экран подряд два символа "А" (латинские)
;------------------------------------------------------------------------
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV AH, 2 ;АН = 2
MOV DL, 41h ;DL = 41h (код символа А)
INT 21h ;вызываем функцию DOS 02h
MOV AH, 2 ;АН = 2
MOV DL, 'A' ;DL = 41h (код символа А)
INT 21h ;вызываем функцию DOS 02h
RET ;Завершение программы
END start
;========================================================================
Функция 06h (Записать символ в STDOUT без проверки на Ctrl+Break)
Вход: | АН | 06h |
DL | ASCII-код символа (кроме 0FFh) |
Выход: | Нет | --- |
Эта функция не обрабатывает управляющие символы (символы CR, LF, HT и
BS выполняют свои функции при выводе на экран, но сохраняются при
перенаправлении вывода в файл) и не проверяет нажатие Ctrl+Break.
Если DL = FFh, то эта функция считывает символ из STDIN без эха, без ожидания
и без проверки на Ctrl+Break. При этом после выполнения прерывания
ZF = 1 и AL = 0, если НЕ была нажата клавиша; ZF = 0 и AL = код
символа, если клавиша была нажата.
Функция 07h (Считать символ из STDIN без эха, с ожиданием и без проверки на Ctrl+Break)
Вход: | АН | 07h |
Выход: | AL | код символа |
Эта функция считывает (ожидает) символ из стандартного входного
устройства и возвращает этот символ в регистр AL. Не фильтрует: не
проверяет на Ctrl+Break, backspace и т.п.
Для ввода расширенного ASCII-кода эту функцию необходимо вызвать
дважды (см. для примера
функцию 01h). Для проверки статуса (если нет
необходимости ожидать нажатие клавиши) следует использовать функцию 0Вh.
Функция 08h (Считать символ из STDIN без эха, с ожиданием и проверкой на Ctrl+Break)
Вход: | АН | 08h |
Выход: | AL | код символа |
Эта функция считывает (ожидает) символ из стандартного входного
устройства и возвращает этот символ в регистр AL. При обнаружении
нажатия клавиш Ctrl+Break выполняется прерывание INT 23h.
Для ввода расширенного ASCII-кода эту функцию необходимо вызвать дважды
(см. для примера
функцию 01h).
Функция 09h (Записать строку в STDOUT с проверкой на Ctrl+Break)
Вход: | АН | 09h |
DS:DX | адрес строки |
Выход: | Нет | --- |
Эта функция выводит на стандартное устройство вывода (например, на
монитор) строку символов. Адрес строки (первого символа строки) должен
быть предварительно записан в DS:DX. Строка должна ОБЯЗАТЕЛЬНО
заканчиваться символом $ (24h), который не будет выведен в STDOUT.
Пример:
;========================================================================
;Эта программа выводит на экран строку "Hello, World!!!"
;------------------------------------------------------------------------
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV AH, 9 ;Номер функции 9
MOV DX, offset stroka ;Адрес строки записываем в DX
INT 21h
RET ;завершение СОМ-файла
stroka DB 'Hello, World!!!$' ;Строка для вывода
END start
;========================================================================
Функция 0Аh (Считать строку символов из STDIN в буфер)
Вход: | АН | 0Ah |
DS:DX | адрес буфера |
Выход: | = | буфер содержит введенную строку |
Для вызова этой функции надо подготовить буфер, первый байт которого
заключает в себе максимальное число символов для ввода (от 1 до 254), а
содержимое, если оно задано, может использоваться как подсказка для
ввода. При наборе строки обрабатываются клавиши Ecs, F3, F5, BS, Ctrl+C,
Ctrl+Break и т.д., как при наборе команд DOS (т.е. Esc начинает ввод
сначала, F3 восстанавливает подсказку для ввода, F5 запоминает текущую
строку как подсказку, Backspace стирает предыдущий символ). После нажатия
клавиши Enter строка (включая последний символ CR (0Dh)) записывается в
буфер, начиная с третьего байта. Во второй байт записывается длина
реально введенной строки без учета последнего символа CR. Большинство
расширенных ASCII-кодов игнорируются. При обнаружении нажатия клавиш
Ctrl+Break выполняется прерывание INT 23h.
Пример:
;========================================================================
;Эта программа считывает строку символов и выводит ее на экран.
;------------------------------------------------------------------------
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV DX, offset buf ;DX = адрес буфера
MOV AH, 0Ah ;AH = номер функции 0Аh
INT 21h ;вызов функции 0Ah
MOV DX, offset crlf ;перевод строки
MOV AH, 9h
INT 21h
;------------------------------------------------------------------------
;Если введенную с клавиатуры строку необходимо вывести на экран, то в
;конец строки нужно записать символ $. Для этого нужно получить адрес
;буфера, узнать длину реально введенной строки и прибавить к полученному
;значению 2, т.к. первые 2 байта содержат служебную информацию. Это
;значение будет адресом байта, который следует за последним символом
;строки. В этот адрес и записывается символ $
MOV DI, offset buf ;DI = адрес буфера
MOV BX, 0h ;ВХ = 0
MOV BL, [DI+1] ;BL = длинa строки
MOV BYTE PTR [DI+BX+2], '$' ;DI+BX+2 - адрес, который следует
;за последним символом строки
MOV DX, offset buf ;DX = адрес буфера
ADD DX, 2h ;прибавляем к DX число 2, т.к. первые
;2 байта не содержат символов строки
MOV AH, 9h ;вызываем функцию вывода строки
INT 21h
;------------------------------------------------------------------------
RET ;завершение программы
crlf DB 0Dh, 0Ah, '$' ;символы перехода на начало новой строки
buf DB 6 ;выделяем буфер для ПЯТИ видимых символов
END start
;========================================================================
Символы считываются до нажатия на клавишу Enter или до достижения
максимальной длины. Обратите внимание, что в этом примере для буфера
выделяется 6 байт, в то время как считано будет только ПЯТЬ видимых
символов. Символ конца строки (CR) не учитывается при вычислении длины
строки, однако, для него необходимо выделять память.
Функция 0Вh (Проверить состояние клавиатуры)
Вход: | АН | 0Bh |
Выход: | AL | 0FFh, если была нажата клавиша 0, если не была нажата клавиша |
Эту функцию удобно использовать перед функциями 01h, 07h и 08h, чтобы не
ждать нажатия клавиши. Вызов указанной функции позволяет проверить, не
считывая символ с клавиатуры, была ли нажата комбинация клавиш
Ctrl+Break. Если это произошло, выполнится прерывание 23h.
Пример:
;========================================================================
;Эта программа выводит символ *, пока не будет нажата какая-либо клавиша.
;------------------------------------------------------------------------
.model tiny
.code
ORG 100h
start: MOV AH, 2 ;АН = 2
MOV DL, '*'
INT 21h ;выводим на экран символ *
MOV AH, 0Bh ;АН = 0Вh
INT 21h ;вызов функции проверки состояния клавиатуры
CMP AL, 0 ;если была нажата клавиша, то заканчиваем
JZ start ;иначе возвращаемся к метке start
RET ;завершение программы
END start
;========================================================================
Эта функция не обрабатывает такие клавиши, как Shift, Ctrl, Alt и т.д.
Однако сочетание клавиш Ctrl+Break обрабатывается.
Функция 0Сh (Очистить буфер и считать символ)
Вход: | АН | 0Ch |
AL | Номер функции DOS (01h, 06h, 07h, 08h, 0Ah) |
Выход: | = | Зависит от вызванной функции |
Эта функция очищает буфер клавиатуры, так что следующая функция чтения
символа будет ждать вода с клавиатуры, а не использовать нажатый ранее и
еще не обработанный символ. Эта функция после очищения буфера вызывает
функцию ввода, указанную в регистре AL. Это заставляет систему ожидать
ввода очередного символа.
Пример:
;========================================================================
;Эта программа ожидает ввода символа. Если символ равен 'y' или 'Y', то
;программа продолжает работу, иначе программа завершается.
;------------------------------------------------------------------------
.model tiny
.code
ORG 100h
start: MOV AH, 9 ;Номер функции 9
MOV DX, offset stroka ;Адрес строки записываем в DX
INT 21h
MOV AH, 0Ch ;Номер функции 0Ch
MOV AL, 7 ;Номер функции 7
INT 21h
CMP AL, 'y' ;Если была нажата клавиша 'y', то
JZ start ;возвращаемся к метке start
CMP AL, 'Y' ;Если была нажата клавиша 'Y', то
JZ start ;возвращаемся к метке start
RET ;завершение программы
stroka DB ' To continue? [Y/N]', 0Dh, 0Ah, '$' ;Строка для вывода
END start
;========================================================================
Функция 0Eh (Установить текущий диск DOS)
Вход: | АН | 0Eh |
AL | номер диска (0 = А, 1 = В и т.д.), который становится текущим |
Выход: | Нет | --- |
Диск, указанный в DL становится текущим (диском по умолчанию) в DOS.
Для проверки следует использовать функцию 19h, с помощью которой можно
узнать текущий диск.
В регистр AL возвращается число дисководов всех типов, включая жесткие
и логические диски.
Функция 19h (Получить текущий диск DOS)
Вход: | АН | 19h |
Выход: | AL | номер текущего диска (0 = А, 1 = В и т.д.) |
Возвращает номер текущего диска.
Пример:
{===================================================================
Программа выдает буквенное обозначение текущего диска (диска,
с которого запускается программа)
===================================================================}
program disk_19h;
uses crt;
var Disk : byte;
Sim : char;
begin
clrscr; writeln;
asm
MOV AH, 19h {Номер функции DOS}
INT 21h {Вызываем функцию}
MOV Disk, AL {Номер диска: 0=А, 1=В и т.д.}
end;
Sim:=chr(65+Disk); {Преобразуем номер диска в буквенное обозначение}
writeln(' Текущим диском является диск ', Sim)
end.
Функция 1Bh (Получить информацию FAT (текущий диск))
Вход: | АН | 1Bh |
Выход: | DS:BX | адрес байта FAT ID, отражающего тип диска |
DX | общее количество кластеров на диске |
AL | количество секторов в кластере |
CX | количество байт в секторе |
Возвращает информацию о размере и типе текущего диска. Размер диска в
байтах равен DX*AL*CX.
Эта функция изменяет содержимое регистра DS.
Пример программы см. в описании функции 1Сh.
Функция 1Сh (Получить информацию FAT (любой диск))
Вход: | АН | 1Ch |
DL | номер диска (0 = текущий, 1 = А и т.д.) |
Выход: | DS:BX | адрес байта FAT ID, отражающего тип диска |
DX | общее количество кластеров на диске |
AL | количество секторов в кластере |
CX | количество байт в секторе |
Эта функция аналогична функции 1Вh. Отличие заключается в том, что в
регистре DL нужно указать диск, о котором вы хотите получить
информацию. Учтите, что с помощью этой функции невозможно получить
достоверную информацию о больших дисках.
Пример:
{===================================================================
Программа выдает некоторые сведение о диске
===================================================================}
program disk_1Ch;
uses crt;
var Claster, Bytes : word;
Sector : byte;
Size : cardinal;
begin
clrscr; writeln;
asm
MOV AH, 1Ch {Номер функции DOS}
MOV DL, 1 {Выбираем диск А}
INT 21h {Вызываем функцию}
MOV Claster, DX {Общее количество кластеров на диске}
MOV Sector, AL {Количество секторов в кластере}
MOV Bytes, CX {Количество байт в секторе}
end;
Size:=Claster*Sector*Bytes; {Вычисляем емкость диска (в байтах)}
writeln(' Всего кластеров: ', Claster);
writeln(' Секторов в кластере: ', Sector);
writeln(' Байт в секторе: ', Bytes);
writeln(' Емкость диска: ', Size, ' байт')
end.
Функция 2Аh (Получить системную дату)
Вход: | АН | 2Ah |
Выход: | AL | день недели (0=Воскр, 1=Пон .. 6=Суб) |
CX | год (с 1980 до 2099) |
DH | месяц (от 1 до 12) |
DL | день (от 1 до 31) |
Эта функция возвращает текущую дату, как она известна системе. В
старых версиях DOS могут быть проблемы.
См. пример в описании
функции 2Сh.
Функция 2Вh (Установить системную дату)
Вход: | АН | 2Bh |
CX | год (с 1980 до 2099) |
DH | месяц (от 1 до 12) |
DL | день (от 1 до 31) |
Выход: | AL | 0, если дата корректна 0FFh, если дата некорректна |
Эта функция устанавливает текущую дату.
Функция 2Ch (Получить время)
Вход: | АН | 2Ch |
Выход: | CH | час |
CL | минута |
DH | секунда |
DL | сотая доля секунды |
Эта функция использует системный таймер, поэтому время изменяется только
18,2 раза в секунду и число в DL увеличивается сразу на 5 или 6.
Пример:
{===================================================================
Эта программа выдает системную дату и время
===================================================================}
program SysDate;
uses crt;
var Day, Month, Date, Hour, Min, Sec : byte;
Year : word;
begin
clrscr; writeln;
asm
MOV AH, 2Ah {АН = 2Аh}
INT 21h {Вызов функции 2Аh - получить дату}
MOV Day, AL {Day = день недели}
MOV Month, DH {Month = месяц}
MOV Date, DL {Date = число месяца}
MOV Year, CX {Year = год}
end;
writeln(' Число: ', Date);
writeln(' День недели: ', Day);
writeln(' Месяц: ', Month);
writeln(' Год: ', Year);
asm
MOV AH, 2Ch {АН = 2Сh}
INT 21h {Вызов функции 2Сh - получить время}
MOV Hour, CH {Hour = час}
MOV Min, CL {Min = минута}
MOV Sec, DH {Sec = секунда}
end;
writeln(' Время: ', Hour, ':', Min, ':', Sec);
end.
Функция 2Dh (Установить время)
Вход: | АН | 2Dh |
CH | час (от 0 до 23) |
CL | минута (от 0 до 59) |
DH | секунда (от 0 до 59) |
DL | сотая доля секунды (от 0 до 99) |
Выход: | AL | FF, если введено несуществующее время, и AL = 00,
если время установлено. |
Функции 2Вh и 2Dh устанавливают одновременно как внутренние часы DOS,
которые управляются системным таймером и обновляются 18,2 раза в секунду,
так и часы реального времени.
Функция 39h (Создать директорию)
Вход: | АН | 39h |
DS:DX | адрес ASCIZ-строки с путем, в котором все директории,
кроме последней, существуют. Для DOS 3.3 и более ранних версий длина строки не должна превышать 64 байта. |
Выход: | CF=0 | если директория создана |
CF=1 | и АХ = 3, если путь не найден |
CF=1 | и АХ = 5, если доступ запрещен |
Функция 3Аh (Удалить директорию)
Вход: | АН | 3Ah |
DS:DX | адрес ASCIZ-строки с путем, где последняя
директория будет удалена (только если она пустая, не является текущей, не занята командой SUBST). |
Выход: | CF=0 | если директория удалена |
CF=1 | и АХ = 3, если путь не найден |
CF=1 | и АХ = 5, если доступ запрещен |
CF=1 | и АХ = 10h, если удаляемая директория - текущая |
Функция 3Вh (Сменить директорию)
Вход: | АН | 3Bh |
DS:DX | адрес 64-байтного ASCIZ-буфера с путем, который станет текущей директорией |
Выход: | CF=0 | если директория изменена |
CF=1 | и АХ = 3, если путь не найден |
Функция 3Ch (Создать файл)
Вход: | АН | 3Ch |
CX | атрибут файла: |
Бит 7: | файл можно открывать разным процессам в Novell Netware |
Бит 6: | не используется |
Бит 5: | архивный бит (1, если файл не сохранялся) |
Бит 4: | директория (должен быть 0 для функции 3Сh) |
Бит 3: | метка тома (игнорируется функцией 3Сh) |
Бит 2: | системный файл |
Бит 1: | скрытый файл |
Бит 0: | файл только для чтения |
DS:DX | адрес ASCIZ-строки с полным именем файла (ASCIZ - это
строка ASCII-символов, оканчивающаяся нулем) |
Выход: | CF=0 | и АХ = идентификатор файла, если не произошла ошибка |
CF=1 | и АХ = 3, если путь не найден |
CF=1 | и АХ = 4, если слишком много открытых файлов |
CF=1 | и АХ = 5, если доступ запрещен |
DS:DX указывает на строку, в которой прописан полный путь к файлу. Если
диск и/или путь не указан, они принимаются по умолчанию.
Если файл уже существует, эта функция все равно открывает его, присваивая
ему нулевую длину. Во избежание этого следует пользовать функцией 5Вh.
Пример:
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV AH, 3Ch ;АН = 3Ch (номер функции DOS)
MOV CX, 00100000b ;атрибут файла
MOV DX, offset stroka
INT 21h
RET ;завершение СОМ-файла
stroka DB 'C:\MyProg\TEST\F_DOS\file.txt', 0
END start
См. также пример для
функции 3Fh.
Функция 3Dh (Открыть существующий файл)
Вход: | АН | 3Dh |
AL | режим доступа: |
Бит 0: | открыть для чтения |
Бит 1: | открыть для записи |
Бит 2: | зарезервирован (0) |
Бит 3: | зарезервирован (0) |
Бит 6-4: | режим доступа для других процессов:
000: режим совместимости (остальные процессы
также должны открывать этот файл в режиме
совместимости)
001: все операции запрещены
010: запись запрещена
011: чтение запрещено
100: запрещений нет |
Бит 7: | файл не наследуется порождаемыми процессами |
DS:DX | адрес ASCIZ-строки с полным именем файла |
CL | маска атрибутов файла |
Выход: | CF=0 | и АХ = идентификатор файла, если не произошла ошибка |
CF=1 | и АХ = 2, если файл не найден |
CF=1 | и АХ = 3, если путь не найден |
CF=1 | и АХ = 4, если слишком много открытых файлов |
CF=1 | и АХ = 5, если доступ запрещен |
CF=1 | и АХ = 0Сh, неправильный режим доступа |
DS:DX указывает на строку, в которой прописан полный путь к файлу. Если
диск и/или путь не указан, они принимаются по умолчанию.
Файл должен существовать.
См. также пример для
функции 3Fh.
Функция 3Eh (Закрыть файл)
Вход: | АН | 3Eh |
BX | идентификатор файла |
Выход: | CF=0 | если не произошла ошибка |
CF=1 | и АХ = 6, если неправильный идентификатор |
Если файл был открыт для записи, то все файловые буфера сбрасываются на
диск, устанавливается время изменения файла и записывается его новая
длина.
См. также пример для
функции 3Fh.
Функция 3Fh (Чтение из файла или устройства)
Вход: | АН | 3Fh |
BX | идентификатор файла |
CX | число байтов |
DS:DX | адрес буфера для приема данных |
Выход: | CF=0 | и АХ = число считанных байтов, если не произошла ошибка |
CF=1 | и АХ = 05h, если доступ запрещен |
CF=1 | и АХ = 6, если неправильный идентификатор |
Если при чтении из файла число фактически считанных байтов в АХ меньше,
чем заказанное число в СХ, то был достигнут конец файла. Каждая следующая
операция чтения, так же как и записи, начинается не с начала файла, а с
того байта, на котором остановилась предыдущая операция чтения/записи.
Если требуется считать (или записать) произвольный участок файла,
используют функцию 42h.
Необходимо всегда сравнивать возвращаемое значение АХ (число прочитанных
байтов) с СХ (запрошенное число байтов)
- если АХ = СХ (и CF = 0) - чтение было корректным и без ошибок
- если АХ = 0 - достигнут конец файла (EOF)
- если AX < CX (но не нулевой), то:
- при чтении с устройства - входная строка имеет длину АХ байт
- при чтении из файла - в процессе чтения достигнут EOF
Если вы читаете с устройства, то АХ возвращает длину считанной строки
с учетом завершающего возврата каретки CR (ASCII 0Dh).
Пример:
;========================================================================
;Эта программа, создает файл, записывает в него строку
;(путь к этому файлу),
;затем читает файл и выводит данные из файла на экран.
;------------------------------------------------------------------------
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV AH, 3Ch ;Создаем новый файл
MOV CX, 0 ;Атрибуты файла
MOV DX, offset path ;Путь к файлу
INT 21h ;Вызов функции 3Ch
PUSH AX ;Помещаем в стек идентификатор файла
MOV AX, 3D02h ;Открываем файл для записи
MOV DX, offset path ;Путь к файлу
INT 21h ;Вызов функции 3Dh
MOV AH, 40h ;Записываем в файл
POP BX ;Идентификатор файла
MOV DX, offset path ;Адрес буфера с данными
MOV CX, 29 ;Будем записывать 29 байтов
INT 21h ;Вызов функции 40h
MOV AX, 3D00h ;Открываем файл для чтения
MOV DX, offset path ;Путь к файлу
INT 21h ;Вызов функции 3Dh
PUSH AX ;Помещаем в стек идентификатор файла
MOV AH, 3Fh ;Читаем из файла
POP BX ;Идентификатор файла
MOV DX, offset buf ;Адрес буфера для данных
INT 21h
MOV AH, 3Eh ;Закрываем файл
INT 21h
;------------------------------------------------------------------------
; Этот участок кода добавляет в конец буфера с прочитанными данными
; символ $, для того, чтобы эту строку можно было вывести на экран
MOV DI, offset buf ;Адрес буфера с прочитанными данными
MOV BX, 29 ;BX = количеству символов в строке
MOV BYTE PTR [DI+BX], '$'
;------------------------------------------------------------------------
MOV AH, 9 ;Выводим строку, считанную из файла
MOV DX, offset buf ;на экран
INT 21h
RET
path DB 'C:\MyProg\TEST\F_DOS\file.txt', 0
buf DB ?
END start
;========================================================================
Примечание:
После окончания работы с файлом, его нужно
обязательно закрыть. Если этого не сделать, то работа с этим файлом из
операционной системы будет невозможна.
Примечание:
Идентификатор файла меняется после выполнения
некоторых функций, поэтому его следует сохранять в стеке или в
переменной, чтобы иметь возможность использовать его в последующих
операциях.
Функция 40h (Записать в файл или устройство)
Вход: | АН | 40h |
BX | 1 для STDOUT или 2 для STDERR |
DS:DX | адрес начала строки |
CX | длина строки (число записываемых байт) |
Выход: | CF | 0 |
AX | число записанных байтов (или код ошибки, если CF=1) |
Эта функция предназначена для записи в файл, но, если в регистр ВХ
поместить число 1, она будет выводить данные на STDOUT, а если ВХ = 2, то
на устройство STDERR, которое всегда выводит данные на экран и не
перенаправляется в файлы.
Нужно всегда сравнивать возвращаемое значение АХ (число записанных
байтов) с СХ (запрошенное число байт для записи)
- если АХ = СХ, то запись была успешной
- если АХ < СХ, то случилась ошибка (скорее всего переполнение)
Эта функция может выводить на экран символ $.
Пример:
;========================================================================
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV AH, 40h ;АН = 40h (номер функции DOS)
MOV BX, 2 ;устройство STDERR
MOV DX, offset stroka
MOV CX, 8 ;длина строки 8 символов (включая знак $)
INT 21h
RET ;завершение СОМ-файла
stroka DB 'Simbol $'
END start
;========================================================================
См. также пример для
функции 3Fh.
Если при записи в файл указать СХ = 0, он будет обрезан по текущему
значению указателя. На самом деле происходит запись в буфер DOS, данные
из которого сбрасываются на диск во время закрытия файла или если их
количество превышает размер сектора диска. Для немедленной очистки буфера
можно использовать функцию 68h.
Функция 41h (Удалить файл)
Вход: | АН | 41h |
DS:DX | адрес ASCIZ-строки с полным именем файла |
Выход: | CF=0 | если файл удален |
CF=1 | и АХ = 02h, если файл не найден |
CF=1 | и АХ = 03h, если путь не найден |
CF=1 | и АХ = 05h, если доступ запрещен |
Удалить файл можно только после того, как он будет закрыт, иначе DOS
продолжит выполнение записи в несуществующий файл, что может привести к
РАЗРУШЕНИЮ ФАЙЛОВОЙ СИСТЕМЫ. Функция 42h не позволяет использовать маски
(символы * и ? в имени файла) для удаления сразу нескольких файлов.
Функция 47h (Определить текущую директорию)
Вход: | АН | 47h |
DL | номер диска (00h - текущий, 01h - A и т.д.) |
DS:DX | 64-байтный буфер для текущего пути (ASCIZ-строка без
имени диска, первого и последнего символов \) |
Выход: | CF=1 | и АХ = 0100h, если операция выполнена |
CF=1 | и АХ = 0Fh, если указан несуществующий диск |
Пример:
;========================================================================
;Эта программа определяет текущую директорию
;------------------------------------------------------------------------
.model tiny
.code
ORG 100h ;начало СОМ-файла
start: MOV AH, 47h ;АН = 47h
MOV SI, offset buf ;Адрес буфера
MOV DL, 0 ;Выбираем текущий диск
INT 21h ;Вызов функции 47h
;------------------------------------------------------------------------
; Этот участок кода добавляет в конец буфера с прочитанными данными
; символ $, для того, чтобы эту строку можно было вывести на экран
MOV DI, offset buf ;Адрес буфера с прочитанными данными
MOV BX, 64 ;BX = количеству символов в строке
MOV BYTE PTR [DI+BX], '$'
;------------------------------------------------------------------------
MOV AH, 9 ;Выводим строку, которая содержит
MOV DX, offset buf ;путь к текущей директории
INT 21h
RET ;завершение программы
buf DB ?
END start
;========================================================================
Если программу запустить из корневого каталога, то она вернет пустую
строку.