Справочник программиста на персональном компьютере фирмы IBM. Дисковые накопители - Чтение из последовательных файлов. Часть 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 ;обработка ошибки