Страница 36 из 41 Средний уровень. Как и для всех файловых операций 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 ;обработка ошибки
|