Глава 5. Дисковые накопители.

Раздел 4. Чтение и запись файла.

5.4.4 Чтение из последовательных файлов.

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

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

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

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

Kаждый раз при вызове функции данные загружаются в память, начиная с первого байта 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 будут содержать новую позицию указателя, как смещение относительно начала файла, т.е., в данном случае, длину файла. Hе забудьте снова вернуть файловый указатель на начало файла, перед тем как читать его; это делается точно таким же образом, за исключением того, что в AL надо поместить 0. Если при выполнении функции 42H возникает ошибка, то устанавливается флаг переноса, а в AX возвращается 1, если неверен номер функции, и 6 - если указан неверный номер файла.

Теперь программа готова для чтения файла. Hадо поместить номер файла в 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 ;обработка ошибки


<~-5.4.3 Запись в последовательные файлы.
Содержание
5.4.5 Запись в файлы прямого доступа.-~>

Сайт управляется системой uCoz