Справочник программиста на персональном компьютере фирмы IBM. Дисковые накопители
Страница 36. Чтение из последовательных файлов. Часть 2


   Средний уровень.


   Как и для всех файловых  операций MS DOS может читать последо-
вательные файлы как методом управляющего блока файла, так и мето-
дом дескриптора файлов. Только  первый  из них имеет функцию спе-
циально предназначенную для чтения последовательных файлов. Метод
дескриптора файлов использует более общую функцию, манипулируя ей
особым образом, требуемым для последовательных файлов.

Метод FCB:
   Функция 14H прерывания 21H читает последовательные файлы. Надо
создать управляющий блок  файла  и  область  обмена с диском, как
объяснено в [5.3.5].  Файл должен быть открыт функцией 0FH преры-
вания 21H [5.3.3].   DS:DX  должны  указывать на первый байт FCB,
после  чего функция 14H будет читать по одной записи из файла при
каждом вызове.  Вы можете установить размер записи по смещению 14
в FCB.  Это надо делать после того, как файл открыт, так как  при
открытии файла DOS вставляет  в  это  поле значение по умолчанию,
равное 128.

   Каждый  раз  при вызове функции данные  загружаются в  память,
начиная с первого байта DTA.  Если DTA используется как небольшой
временный буфер, то перед чтением следующей записи содержимое DTA
должно быть перенесено в область данных файла, отведенную в памя-
ти.   Можно наоборот установить указатель DTA на стартовый  адрес
памяти, начиная с которого будет размещаться файл, а после чтения

каждой записи указатель увеличивать на размер записи, с тем чтобы
он указывал на место, где должна быть следующая запись.
   Установкой полей  текущей  записи  (DB,  смещение 1FH) и блока
текущей  записи (DW, смещение 0CH) отличными от нуля,  последова-
тельный может читаться,  начиная  с  любого требуемого места (ус-
тановка  должна быть сделана после открытия FCB).  После  каждого
чтения поле текущей записи  автоматически  увеличивается  на 1, а
после  чтения 128 записей увеличивается поле текущего блока.  При
возврате AL равен 0, если вся запись успешно прочитана. При обна-
ружении конца файла AL будет содержать 1, если функция 14H вообще
не возвратила данных и 3 - если запись прочитана частично.
   В приведенном примере из файла считываются две записи и после-
довательно  помещаются  в нужную область памяти.   Размер  записи
установлен равным 256 байтам.  Записи считываются в цикле и после
того,  как  первая  запись считана, указатель на  DTA  изменяется
таким образом, чтобы он  указывал  на следующий пустой байт в об-
ласти данных.

;---помещаем FCB в сегмент данных
FCB          DB  0,'OLDDATA DAT', 25 DUP(0)
DATA_AREA    DB  512 DUP (?)    ;используем как DTA

;---устанавливаем DTA на начало области данных
   LEA  DX,DATA_AREA      ;DS:DX указывают на DTA
   MOV  DI,DX             ;сохраняем копию
   MOV  AH,1AH            ;функция установки DTA
   INT  21H               ;устанавливаем DTA
;---открываем файл
   LEA  DX,FCB            ;DS:DX указывают на FCB
   MOV  AH,0FH            ;функция открытия файла
   INT  21H               ;открываем файл
   CMP  AL,0              ;проверка на ошибку
   JNE  OPEN_ERROR        ;
;---устанавливаем размер записи 256 байт
   LEA  BX,FCB            ;DS:DX указывают на FCB
   MOV  AX,256            ;размер записи
   MOV  DS:[BX]+14,AX     ;посылаем в поле размера записи
;---чтение данных
   MOV  CX,2              ;число читаемых записей
NEXT_REC:   MOV  AH,14H   ;функция чтения файла
   LEA  DX,FCB            ;DS:DX указывают на FCB
   INT  21H               ;читаем одну запись
   CMP  AL,0              ;все в порядке?
   JE   CONTINUE          ;
   CMP  AL,2              ;проверка на ошибку
   JE   READ_ERROR        ;   .
    .

CONTINUE:  ADD  DI,256    ;увеличиваем указатель
   MOV  DX,DI             ;DX указывает на новую DTA
   MOV  AH,1AH            ;функция установки DTA
   INT  21H               ;устанавливаем DTA

   LOOP NEXT_REC          ;идем на чтение следующей записи
;---позднее, закрываем файл
   LEA  DX,FCB            ;DS:DX указывают на FCB
   MOV  AH,10H            ;функция закрытия файла
   INT  21H               ;закрываем файл
   CMP  AL,0FFH           ;проверка на ошибку
   JE   CLOSE_ERROR       ;

Метод дескриптора файлов:
   Функция 3FH прерывания 21H может читать данные из файла после-
довательно. Эта функция используется для любого чтения из файла с
помощью метода дескриптора файлов, включая файлы прямого доступа.
Файл должен быть открыт  функцией  3DH прерывания 21H с кодом 0 в
AL, если он открывается только для чтения, и с кодом 2 - если  он
открывается для чтения и записи.  При открытии файловый указатель
автоматически устанавливается на первый байт файла.  Функция чте-
ния из файла указывает сколько байтов должно быть считано и после
того  как это сделано файловый указатель указывает на байт,  сле-
дующий за последним  считанным  байтом,  подготавливая  следующее
обращение к функции. Отметим, что файловый указатель уникален для
каждого файла - операции над  другими файлами не меняют его пози-
цию.
   Программа  может создать небольшой временный буфер,  размером,
скажем, 512 байт, и постоянно  вызывать  функцию чтения, не забо-
тясь о позиции файлового указателя. Другой метод состоит в считы-
вании всего файла прямо в  то  место  памяти,  где он должен быть
расположен.  В этом случае надо просто потребовать, чтобы функция
прочитала больше байтов, чем реально  содержится в файле, так как
чтение прекращается при достижении последнего байта файла. Однако
Вам необходимо знать точную длину файла, чтобы знать где кончают-
ся данные в буфере, в который Вы считали файл.
   Размер  файла можно определить, сдвинув файловый указатель  на
конец файла.  Это надо  сделать  сразу  же  после открытия файла.
Поместите  в  AL код 2 и вызовите функцию 42H,  для  того,  чтобы
сдвинуть указатель на конец  файла.   CX и DX должны содержать 0,
так  как в противном случае указатель будет сдвинут с конца файла
на величину, которая содержится  в  этих  регистрах. При возврате
DX:AX будут содержать новую позицию указателя, как смещение отно-
сительно начала файла, т.е.,  в  данном  случае,  длину файла. Не
забудьте  снова вернуть файловый указатель на начало файла, перед
тем как читать его; это делается точно  таким же образом, за иск-
лючением  того,  что в AL надо поместить 0.  Если при  выполнении
функции 42H возникает ошибка, то устанавливается флаг переноса, а
в AX возвращается 1, если неверен номер функции, и 6 - если  ука-
зан неверный номер файла.
   Теперь программа готова для чтения файла. Надо поместить номер
файла в BX, а требуемое число байтов в CX и выполнить прерывание.
При возврате AX будет содержать число реально прочитанных байтов.
Если AX равен нулю, то достигнут конец файла.  При других ошибках
устанавливается флаг переноса, а AX  содержит 5 - при ошибке обо-
рудования  и  6 - если указан неверный номер файла.  В  следующем
примере в буфер памяти  считывается  весь  небольшой файл. Для у-
добства  буфер располагается в сегменте данных,  что  существенно

увеличивает размер программы на диске.   В своих программах лучше
создавать буфер, используя технику распределения памяти,  описан-
ную в [1.3.1].

;---в сегменте данных
PATH        DB   'A:FILENAME.EXT'0   ;строка пути к файлу
DATA_BUFFER DB   1000 DUP (?)        ;буфер данных
HANDLE      DW   ?                   ;номер файла
FILESIZE    DW   ?                   ;размер файла

;---открываем файл
   LEA  DX,PATH            ;DS:DX указывают на путь
   MOV  AL,0               ;код открытия для чтения
   MOV  AH,3DH             ;функция открытия файла
   INT  21H                ;открываем файл
   JC   OPEN_ERROR         ;проверка на ошибку
   MOV  HANDLE,AX          ;запоминаем номер файла
;---устанавливаем файловый указатель на конец файла
   MOV  AH,42H             ;функция установки указателя
   MOV  AL,2               ;код для конца файла
   MOV  BX,HANDLE          ;номер файла
   MOV  CX,0               ;смещение равно нулю
   MOV  DX,0               ;
   INT  21H                ;устанавливаем указатель
   JC   POINTER_ERROR1     ;обработка ошибки
   MOV  FILESIZE,AX        ;запоминаем размер (меньше 64K)
;---возвращаем указатель на начало
   MOV  AH,42H             ;номер функции
   MOV  AL,0               ;код для начала файла
   MOV  CX,0               ;смещение равно нулю
   MOV  DX,0               ;
   INT  21H                ;устанавливаем указатель
   JC   POINTER_ERROR2     ;обработка ошибки

;---читаем весь файл
   MOV  AH,3FH             ;номер функции чтения файла
   MOV  BX,HANDLE          ;номер файла
   MOV  CX,FILESIZE        ;число считываемых байтов
   LEA  DX,DATA_BUFFER     ;DS:DX указывают на буфер
   INT  21H                ;читаем файл
   JC   READ_ERROR         ;обработка ошибки

;---позднее, закрываем файл
   MOV  BX,HANDLE          ;номер файла
   MOV  AH,3EH             ;функция закрытия файла
   INT  21H                ;закрываем файл
   JC   CLOSE_ERROR        ;обработка ошибки

 
« Предыдущая статья   Следующая статья »