Глава 8. Работа с файлами под управлением MS DOS.

Что имеем - не храним; поте­рявши - плачем.

Козьма Прутков.

I

Работа с файлами, по правде единственное, что представлено в системе

функций MS DOS достаточно полно. Редко какая программа обходится без обращения к диску. Именно здесь встречается больше всего проблем и ошибок. Я не ставлю своей целью дать всестороннее изложение данного вопроса. Поэтому оставляю в стороне такой вопрос, как работа с файлами методом FCB. Данный метод устарел с того мо­мента, как DOS научилась работать с каталогами. Однако для выполнения условий совместимости он до сих пор представлен в операционной системе. Всех желающих познакомиться С этим подходом отсылаю к замечательной книжке Р. Журдена [5].

Метод работы с файлами в системе MS DOS называется методом описателя или дескриптора. Идея работы с файлами методом описателя в MS DOS заключается в следующем:.

1. Вначале файл должен быть открыт, при этом должно быть указано имя файла -либо полное (полный путь), либо краткое. В последнем случае файл берется из текущего каталога. В конце имени файла должен стоять код G.

2. После того как файл был удачно открыт, ему присваивается описатель - число от 5 до 256. Дальнейшая работа будет вестись теперь через этот описатель. В PSP программы, по смещению 18Ннаходится таблица описателей. Под нее от­водится 20 байт, поэтому программа не может открыть одновременно больше 20 файлов. Байт, содержащий FFH, соответствует свободному описателю. Ис­пользование этой таблицы см. вглаве 19и в конце данной главы. Крометого, в PSP по смещению 32Н (слово) хранится размер таблицы описателей, а в четы­рехбайтовой ячейке со смещением 34Н записан полный адрес этой таблицы (по умолчанию 18Н и сегментный адрес PSP).

3. В конце работы файл следует закрыть.

4. Помните,чтопризнакомошибкипривыполнениифункцииГХ)8являетсявзве-денный флаг С (переноса).

Заметим, что описатель файла естьлишь некий индекс, по которому можно найти область памяти, выделяемую для работы с данным файлом. Эта область памяти необ-ходимадля того, чтобы буферизовать ввод и вывод в этот файл, что делает работу с ним более быстрой. При записи в файл данные записываются сначала в буфер и, толь­ко он переполнен, записываются на диск. Таким образом, значительно увеличи­вается скорость записи на диск. При закрытии файла содержимое буфера записи сбра­сывается на диск, и далее этот буфер может использоваться для работы с другим фай­лом. Аналогично работает буферизация при чтении из файла. Читателю, я надеюсь,теперь понятно, почему данные незакрытого файла могут оказаться потерянными. Должно быть ясно также и то, почему при открытии необходимо указывать режим работы с файлом (чтение, запись, то и другое). Ведь при открытии ввделяются буфера отдельно на чтение и запись. В MS DOS имеется функция 68Н, с помощью которой можно сбрасывать буфера, выделенные для записи, на диск, не закрывая файла. Эту функцию часто используют для того, чтобы обезопасить себя от возможной потери данных. Аналог ее имеется во всех языках высокого уровня.

Итак, все по порядку.

1. Открыть файл. Рассмотрим фрагмент.

LEA сегменте данных О

/если краткое имя, то берется текущий каталог

MOV для чтения    и записи

/если G для чтения,  1 для записи открытия файла

INT 21Н /открываем файл

JC   ERRO       /ошибка, если поднят флаг С,  в АХ код ошибки /если ошибки нет, то в АХ описатель файла /для будущей работы следует его сохранить

Имейте в виду, что ошибка обязательно появится, если такого файла не существу­ет (в указанном каталоге, естественно). Но если файла нет, то следует его создать.

Несколько слов об описателях. Количество описателей в системе задается в файле CONFIG.SYS: FILES=N. Причем значение меняется от 5 до 255. Если такой строки нет, то по умолчанию системе дается восемь описателей (8 одновременно открытых файлов, включая и всегда открытые, см. главу 6). Надо, однако, иметь в виду, что коли­чество одновременно открытых файлов (включая предопределенные файлы) не мо­жет превышать 20, хотя количество описателей может быть больше. Поскольку 5 пер­вых описателей всегда открыто, то получается, мы сможем одновременно открыть, на самом деле не более 15файлов. В конце главы будет показано, как можно решить

данную проблему.

2. Создать файл. Фрагмент для создания файла аналогичен фрагменту в пункте 1 (только теперь функция ЗСН), но есть и отличие:

а) файл всегда открывается для чтения и записи;

б) в СХ следует поместить атрибут файла (надеюсь, Вы знаете, что такое атри­бут файла), например, 0 или 32 для обычных файлов (напомню, что атрибут 32 означает, что копия с этого файла с помощью программы BACKUP не

Создавая файл, помните, что если файл с таким именем уже су­ществует, то содержимое его будет потеряно. Поэтому, прежде чем созда­вать файл с помощью данной функции, убедитесь, что в заданном каталоге его нет. Есть, однако, функция 5ВН, которая отличается от ЗСН только тем, что, если файл уже существует, содержимое его не уничтожается, а взводит­ся флаг ошибки С.

3. Закрыть файл.

/функция закрытия файла

/в ВХ должен находиться описатель файла ; выполняем закрытие /если флаг взведен,   то ошибка

MOV INT

JC ERROR

При закрытии файла на диск сбрасываются все буфера. Обновляется длина файла, время и дата последней корректировки.

4. Чтение и запись в файл. При работе с файлами на ассемблере помните,' что еди­ничной записью является байт. Все записи имеют номера от 0 до Ь-1, где Ь длина файла. При открытии файла указатель устанавливается на запись 0. При чтении или записи указатель автоматически передвигается на п байт (где п -число прочитанных или записанных байт). Рассмотрим фрагмент, демонстри­рующий запись в файл (чтение из файла —см. главу 6).

функции записи в файл

LEA DX,BUF в сегменте данных

MOVCX, 500      /сколько записывать байт из буфера

JC    ERROR        /ошибка если флаг взведен и в АХ код ошибки

При чтении файла (функция ЗБН) в АХ помещается считанное количество байт. Поэтому следует каждый раз сравнивать АХ и СХ. Если АХ<СХ, то обычно это озна­чает, что в процессе чтения произошел переход через конец файла (но не забывайте про флаг С!). При записи в файл ситуация аналогична, но в этом случае неравенство содержимого АХ и СХ будет означать, что в процессе записи произошла ошибка.

Как я уже говорил, при чтении или записи указатель автоматически передвигается на следующий за считанным блоком байт. Используя функцию 42Н, можно перемес­титься к любому байту файла. Ниже дается полное описание этой функции.

АН 42Н

ВХ описатель файла

СХ:БХ на сколько передвинуть: СХ*65536+БХ ЛЬ как передвигать

0 начало  файла  + СХ:БХ,

1 текущий файл + СХ:ЭХ,

2 конец файла  + СХ: ЭХ

Если флаг переноса установлен, то в АХ помещен код ошибки, в противном слу­чае AX:DX показывает новую позицию в файле.

С помощью данной функции легко определить длину файла: обнуляем DXh СХи вызываем функцию с AL=2, тогда в AX:DX будет содержаться длина файла.

Вот, в общем, все основные функции для работы с файлами. Надеюсь, что с осталь­ными Вы легко справитесь сами, используя справочник функций DOS в Приложении 7.

Перечислю еще несколько функций, которые без сомнения понадобятся Вам при работе с файлами: 1. Поиск первого вхождения файла, 2. поиск последующего вхождения фай­ла, 3. удалить файл, 4. переименовать файл, 5. изменить или получить атрибут файла, 6. изменить или получить время и дату создания (последней модификации) файла, 7. со­здать каталог, 8. удалить каталог, 9. сменить каталог. Примеры на использование некото­рых из этих функций Вы найдете, как в данной главе, так и далее в книге.

II

Итак, рассмотрим первый пример (Рис. 8.1). Здесь представлена программа вывода на экран последней строки текстового файла. Алгоритм основан на том, что разделителем между строками втекстовомфайлеявжется последовательность кодов 13, Ю.Вэтомвесь фокус. Мы переходим в конец файла, а затем ищем начало последней строки по коду 10. Код 13 скажет нам о конце строки. Так как у последней строки может не быть приписки 10,13, то конец в этом случае определим по неравенству содержимого АХ и СХ.

; DS на сегмент данных

data segment path db "PRIMER.TXT",0

buf db ? CX_ DW ? dx_ dw ? data ends

sseg  segment stack db   200 DUP(?)

sseg ends

code segment

assume CS:CODE,   DS: DATA, SS:SSEG begin:

mov AX,DATA

MOV DS,AX ;открываем файл

MOV AX,3D00H

LEA  DX,PATH

INT 21H ;если ошибка, то

JC EXIT ;на конец файла,

MOV ВХ,АХ

XOR СХ,СХ

XOR  DX, DX

MOV AX,4202H

INT 21H ;три байта от конца

MOV CX,DX

MOV DX,AX

MOV AX,4200H

SUB DX,3 ■■

;имя файла  (текущий каталог) ; буфер для считывания байта из /временно храним СХ ; временно храним БХ

файла

заканчиваем

определяя длину

(вдруг в конце тоже стоит

. ■ SBB СХ, о MOV СХ_,СХ MOV DX_,DX

INT 21H

LOO:

;читаем один байт MOV АН,3FH LEA DX,BUF

MOV CX,1 INT 21H

/проверяем,   не  конец ли предыдущей строки

CMP BUF,10

JZ OUT_STR ; сдвигаем на  один байт к началу

SUB DX_, 1

SBB СХ_, О

MOV DX,DX_

MOV CX,CX_

MOV AX,4200H

INT 21H

JMP  SHORT LOO ;здесь выводим строку OUT_STR:

MOV AH,3FH

LEA DX,BUF

MOV CX,1

INT  21H '

CMP BUF,13

JZ CLOSE

CMP AX,CX

JNZ CLOSE выводим

MOV DL,BUF

MOV AH,2 ■

INT 21H

JMP OUT_STR CLOSE:

MOV

INT 21H

EXIT:

MOV AH,4CH

INT 21H CODE ENDS

END BEGIN ■

конец ли строки? конец ли файла?

файл

Рис. 8.1. Вывод на экран последней строки текстового файла.

Следующий примердемонстрируетвыводна экран содержимого текущего подка­талога (имен файлов, кроме скрытых, и подкаталогов). На досуге подумайте, как усо­вершенствовать программу - вывод по алфавиту, выделение подкаталогов ит.п. Шаб­лон для поиска может быть Вами изменен, и в соответствии с ним будут выдаваться те или иные имена файлов.

DATA SEGMENT

PATH DB  "*.*",О ;шаблон для поиска

DTA DB 50  DUP(?> ;буфер для размещения текущей

; информации для функций 4ЕН и 4FH

DATA ENDS

SSEG   SEGMENT STACK DB   200 DUP(?)

SSEG ENDS CODE SEGMENT

ASSUME CS:CODE,   DS:DATA, SS:SSEG

BEGIN:

MOV AX,DATA

MOV DS,AX /устанавливаем буфер DTA

MOV АН,1AH

LEA  DX,DTA

INT 21H

; вообще говоря можно  пользоваться  готовым буфером DTA, /устанавливаемый системой в   PSP  со  смещением 80Н /ищем первое вхождение CALL FIND_F

JC      EXIT ; нет файлов  - выходим

DIR:

; ищем последующие вхождения

CALL FIND_N

JC EXIT имя

CALL OUT_NAME

JMP    SHORT DIR

;конец

EXIT:

MOV АН,4CH

INT 21H

поиска  первого вхождения

FIND_F PROC

LEA  DX, PATH ■ MOV АН,4EH

■в СХ атрибут файла,   установим биты так,

поиск осуществлялся по

скрытых и меток тома MOV  СХ,110101В

INT 21H RET FIND_F ENDP

поиска последующих

FIND_N PROC

после  выполнения функции всем файлам,

вхождений

4ЕН Вы не меняете DTA

;то следующая  строка не LEA   DX,DTA MOV АН,4FH

INT 21H RET FIND_N ENDP

;процедура вывода имени

обязательна

имя OUT_NAME

MOV MOV

OUT S:

расположено PROC

BX,1EH

2

файла

буфере  DTA,   по  смещению 1ЕН

MOV CMP

JZ INT INC JMP

KON:

;перевод

MOV

INT

MOV

INT

RET OUT_NAME CODE ENDS

END BEGIN

DL,[DTA+BX] DL, 0

KON 21H

BX

SHORT OUT S

строки DL, 13 21H DL, 10

21H

ENDP

в

Рис. 8.2. Вывод содержимого подкаталога на экран.

На Рис.8.3 приведена программа, которая осуществляет слияние двух произволь-ныхфайлов: кфайлуРШМЕК2.ТХТдобавляетсяфайлРК1МЕЯ1.ТХТ. Обращаю Ваше внимание нато, что в различныхпрограммах мы берем различные размеры буферов.

Этим подчеркивается, что размер буфера несущественен для представленного алго­ритма. Он влияет лишь на быстроту выполнения программы: при большем буфере программа выполняется быстрее.

DATA SEGMENT

РАТН1 DB  1PRIMER1.TXT',0 /имя первого файла

PATH2  DB   ' PRIMER2 . TXT', 0   /имя второго файла   (куда добавлять) HANDL1 DW ? /описатель первого файла

HANDL2 DW ? /описатель второго файла

BUFER    DB   1000   DUP(?) /буфер

EOF   DB 0 /если 1, то в процессе чтения

/достигнут конец файла

DATA ENDS

SSEG SEGMENT STACK

DB  200 DUP(?) SSEG ENDS CODE SEGMENT

ASSUME CS:CODE,  DS:DATA, SS:SSEG BEGIN:

MOV AX,DATA

MOV DS,AX /открываем первый файл

MOV AH,3DH

MOV AL,0

LEA DX,PATH1

INT 21H

JC EXIT

MOV HANDL1,AX /открываем второй файл MOV AH, 3DH MOV AL,1 LEA  DX,PATH2 INT 21H

JC CLOSE1

MOV HANDL2,AX /указатель второго файла  на конец

MOV АН,42Н

MOV BX,HANDL2

XOR CX,CX

XOR DX,DX

MOV AL,2

INT 21H /готовим  регистры ■

LEA  DX,BUFER

MOVCX, 1000 ;блок копирования LOO: ,-читаем

MOV BX/HANDL1

MOV AH,3FH

INT 21H

CMP AX,CX

JZ NORM

MOV CX,AX

MOV EOF, 1

NORM: ;пишем

MOV

MOV AH, 4OH INT 21H CMP EOF, 0 JZ LOO ; закрываем второй файл CLOSE2:

MOV АН, ЗЕН MOV ВХ,HANDL2 INT 21H ; закрываем первый файл CLOSE1:

MOVAH,3EH MOV ВХ,HANDL1 INT 21H ; выход в DOS EXIT:

MOV АН,4CH

INT 21H

CODE ENDS

END BEGIN байт

;достигнут конец файла

достигнут ли конец

Рис. 8.3. Слияние двух файлов.

Следующая программа обрабатывает заданный в командной строке файл таким образом, что все прописные латинские буквы преобразуются в заглавные. Блок, ана­лизирующий командную строку, здесь идентичен аналогичному блоку в программе на Рис. 7.6 (Глава 7). В данной программе обратите особое внимание на механизм про­смотра файла. Этот механизм в значительной степени основан на том, что размер бу­фера не превышает 255 байт. Попробуйте изменить программу так, чтобы можно было взять больший размер буфера.

CODE SEGMENT

ASSUME CS:CODE, ORG 100H

BEGIN:

JMP BEG

DS:CODE

'Нет параметров.',13,10, 1 $' 'Файл не найден.',13,10,'$' ;путь к файлу ;буфер для чтения

строки

DB DB

DB 80 DUP(O) DB   160 DUP(?)

TEXT1 TEXT2 PATH BUF BEG:

;блок анализа командной XOR SI,SI XOR DI,DI MOV  DL, 1

файла

LOO:

CMP  BYTE   PTR [81H+SI],ODH

JZ

NO_PAR

MOV

CMP AL, ' '

JZ SPACE

XOR  DL,DL

MOV [PATH+DI],AL

INC

JMP SHORT L001

SPACE:

OR JZ

LOOl:

INC SI

JMP SHORT LOO

NO_PAR:

OR

DL,DL /если DL=0 тогда первый параметр NO_PAR

закончился

SI, SI

JNZ CONT /сообщение,   затем выходим MOV DX,OFFSET TEXT1 MOV AH,9

INT 21H JMP EXIT

открытие

CONT:

/открыть файл

LEA  DX,PATH MOV AX,3D02H

INT 21H

ли параметр

преобразование файла

JNC NORM

MOV DX,OFFSET TEXT2 MOV AH,9

INT 21H

JMP EXIT

NORM :

MOV BX,AX

XOR POVT:

;читать участок файла LEA DX,BUF MOV AH,3FH

MOV

INT 21H

MOV AH,AL

LEA SI,BUF

CMP AL, 0 /просматриваем буфер L02 :

ZER

;в 01 будет хранится начало считываемого участка в буфер

/размер буфера

преобразуем латинский шрифт

L01;

JZ

CMP BYTE PTR

JB . L01

CMP BYTE PTR

JA L01

SUB BYTE PTR

INC

[SI],97 [SI],122 [SI],32

SI DEC AL JMP SHORT

L02

ZER:

PUSH AX

указатель   файла назад MOV АХ,4200Н X0R СХ,СХ

MOV начала

INT 21H

пишем буфер на диск /количество записанных байт может, вообще /быть больше 160 MOV АН,40Н

POP cx PUSH cx

MOV CL,CH XOR СН,СН

считанного участка

говоря,

LEA DX,BUF INT   21H ' /проверяем, не достигнут ли конец файла POP AX MOV   AL, АН XOR   АН,АН ADD   DI, AX

CMP AL,160 /сравниваем с размером буфера

JZ POVT /закрыть файл MOV АН,ЗЕН

INT 21H

EXIT:

RET CODE ENDS

END BEGIN

Рис. 8.4. Программа инвертирования прописных латинских символов в файле. III

Использование описателей файлов таит в себе достаточно интересные возможности. Частично мы уже коснулись этого вопроса, когда выводили информацию на экран при помощи стандартной функции записи в файл (Глава 6, Рис. 6.1). Другие возможности ме­тода описателей связаны с использованием функций 45Ни 46Н.Рассмотрим эти функции.

Дублировать .описатель.

Вход:

АН-45Н,

ВХ - описатель (например, вывода на экран). Выход:

если нет ошибки (флаг не взведен)

АХ - новый описатель иначе код ошибки.

Переназначить описатель.

Вход:

АН-46Н,

ВХ - уже существующий описатель, СХ - исходный описатель.

Выход:

АХ - код ошибки, если флаг взведен.

Впервые на практике с этой проблемой я столкнулся лет 10 назад. Мне понадоби­лось запустить из программы архиватор, причем часть вывода (не информативная)должна была быть блокирована, а часть должна была выводиться в файл. С помощью указанных функций проблема решалась изящно и просто. Вот алгоритм решения.

1. Дублируем описатель вывода на экран (1).

MOV АН,45Н MOVBX,l INT 21H

Сохраним описатель.

2. Открываем файл.

3. Переназначаем описатель вывода на экран. MOV АН,4бН

MOV СХ, 1

INT 21Н    ;при этом в ВХ должен находиться описатель файла

4. Закрываем описатель файла. Теперь весь стандартный экранный вывод пойдет

в файл.

5. Запускаем архиватор.

6. Переназначаем описатель 1 на старое значение (см. п. 1).

7. Закрываем описатель, полученный в п. 1.

Внимательный читатель заметит, однако, что проблема решена не полностью. Дело в том, что часть информации может выводиться с помощью функций стандартного вывода на экран. В обычных архиваторах и происходит. В частности так выводит­ся информация о динамике работы архиватора. Эта часть информации может быть блокирована путем перехвата прерывания ЮН, через которое идет весь вывод на эк­ран, разумеется, кроме прямого.

И еще один пример - Рис.8.5.

data segment

PATH DB '1.TXT',О ; файл для вывода

BUF DB ? ; буфер

DATA ENDS STA SEGMENT STACK

DB   100 DUP(?) STA ENDS CODE SEGMENT

ASSUME CSrCODE,  DS:DATA, SS:STA BEGIN:

MOV AX,DATA

MOV DS,AX ;открываем файл

MOV АН,3CH

LEA DX,PATH

MOV CX,0 '

INT 21H •

JC KONEC

MOV ВХ,АХ ;если ошибка - конец /•сохранить описатель

буфер

LEA DX,BUF

READ:

; читаем со   стандартного  устройства   один символ PUSH ВХ MOV ВХ,0 MOV СХ,1 MOV АН,3FH INT 21H POP ВХ

JC    CLOSE   /если не удалось прочесть,   то конец

mov sijcx

MOV DI,AX MOV CX,AX

; пишем в файл MOV АН,40Н LEA  DX,PATH

INT 21H

JC CLOSE   ; если не удалось,   то конец '   CMP СХ,АХ ■   JNZ CLOSE

CMP SI,DI

JZ READ ;закрываем файл CLOSE:

MOV АН,3EH

INT 21H KONEC:

MOV AH,4CH

INT 21H

CODE ENDS

END BEGIN

Puc. 8.5. Пример использования описателя стандартного ввода.

Эта простая программа выполняет следующие действия: получает символы со стандартного устройства ввода и отправляет их в файл 1 ,ТХТ. Прекратить выполне­ние программы можно, нажав Ctrl+C. Таким образом, текст можно непосредственно с клавиатуры отправлять в файл. На примере этой программы можно проверить и такое интересное свойство операционной системы MS DOS, как конвейеризация. Пусть от­транслированная программа будет называться INP.EXE. Наберите строку: DIR|uMP - в результате в файл 1 .ТХТ будет выведен список файлов текущего каталога.

Как видно из данной главы, работа с файлами всецело основана на функциях DOS. Полный список этих функций приведен в Приложении 7.

IV.

Теперь рассмотрим вопрос о том, как программа может одновременно работать с большим количеством (больше 15)файлов (см. начало Главы). Для этого необходимо:

1. В файл CONFIG.SYS поместить строку FILES=N, где N - нужное количество одновременно открытых файлов. Как мы уже разбирали, этого недостаточно, т.к. таблица файлов находится в PSP и может содержать не более 20 описателей.

2. Скопировать таблицу на новое место и указать ее новый адрес и размер. Следу­ющая программа демонстрирует это.

DSEG SEGMENT

NUM    DB О ;новая таблица файлов

DESC  DB  50 DUP(OFFH) для  открытия файлов /добавляя в 4-ю и 5-ю позиции различные символы

будем   генерировать   новые файлов

PATH DB 'file',0, О, О

DSEG ENDS

STSEG SEGMENT STACK

dw  50 DUP(?)

STSEG ENDS CSEG SEGMENT

ASSUME cs:cseg,  ds:dseg, ss:stseg BEGIN:

MOV ax,dseg

MOV ds,ax

MOV num, 0 ; создаем новую таблицу файлов

CALL open_tab ; готовим регистры для открытия файлов

XOR СХ,СХ

LEA   dx,path

;вначале SI+4 указывает на четвертую позицию в имени файла MOV SI,DX MOV bl,65

/попытка открыть одновременно   40 файлов LOO: .

MOV АН,ЗСН

mov[si+4],bl • . ' ,

INT 2 III

JC   _END     ; если ошибка создания, то конец CMPBL, 1 Z'

jnz no

INC SI

; теперь  SI+5 указывает на  5-ю позицию в имени файла MOV BL,65

N0:

INC BL INC NUM

CMP NUM., 40

JNZ  LOO не  сорок,  то продолжим

__END:

сколько  файлов  было реально открыто MOV    AL,NUM

CALL DISP_BYTE

MOV AX,4C00H

INT 21H

процедур /процедура вывода байта в AL DISP_BYTE PROC NEAR

XOR

AH, AH

MOV

BL,100

DIV

BL

MOV

SI, AX

MOV

AL, AH

XOR

AH, AH

MOV

BL, 10

DIV

BL

MOV

BX,AX

MOV

DX, SI

MOV

AH, 2

ADD

DL, 48

INT

21H

MOV

DL, BL

ADD

DL, 48

INT

21H

MOV

DL, BH

ADD

DL, 48

INT

21H

RETN

DISP_BYTE ENDP

/процедура открытия новой таблицы файлов OPEN TAB   PROC NEARкопируем таблицу файлов       новое место

MOV

CX,20

LEA

DI,DESC

MOV

SI,18H

MOV

AL,ES:[SI]

MOV

DS:[DI],AL

INC

SI

INC

DI

LOOP

LOOl

; здесь указываем новый размер и адрес таблицы ; размер таблицы описателей

MOV   WORD PTR ES:[32H],50 ;положение таблицы

MOV ES:[36H],DS

MOV   WORD PTR ES: [34H],OFFSET DS:DESC

RETN OPEN_TAB ENDP CSEG ENDS

END BEGIN

Рис. 8.6. Пример использования своей таблицы файлов.

Данная программадолжна одновременно открывать 40 файлов при условии, что в файле CONFIG.SYS стоит строка FILES=N, rfleN>45. При окончании работы про­грамма выводит количество одновременно открытых файлов. При успешном завер­шении это число равно 40. Процедура создания новой таблицы файлов называется OPEN_TAB. Если отключить эту процедуру, то количество одновременно открытых файлов будет равно 15 (илидаже меньше). Поэкспериментируйте с этим. Кстати, при­близительно так работают многие системы управления базами данных для операци­онной системы MS DOS, которые позволяют одновременно работать с ^ большим коли­чеством открытых файлов. Новую таблицу файлов мы поместили в сегмент данных программы, но С тем же успехом могли бы выделить для этой таблицы область памяти динамически (см. управление памятью в Главе 11).

Сходным образом проблема работы с большим количеством одновременно откры­тых файлов решается посредством функции 67Н DOS (см. Приложение 7). Данная функция автоматически выделяет место для новой таблицы и возвращает указатель на

эту область (сегментный адрес в ES).