Рассмотрим сначала случай полной перезаписи файла. После того,
как файл открыт функцией 3CH, файловый указатель устанавливается
равным нулю, поэтому нет нужды устанавливать его. Поместите номер
файла в BX, а число записываемых байтов в CX. Затем установите
DS:DX на первый байт выводимых данных и выполните функцию 40H
прерывания 21H. При возврате, если флаг переноса установлен, то
была ошибка и AX содержит 5, если была ошибка дискового накопите-
ля и 6 - если неверный номер файла. В противном случае, AX будет
содержать число реально записанных байтов; при несовпадении ве-
роятнее всего проблема состоит в том, что диск полон. Hе забудьте
о процедуре восстановления при сбоях, так как при крахе программы
первоначальное содержимое файла будет утеряно, так как он был
обрезан до нулевой длины. Kак проверять дисковое пространство
описано в [5.1.2]. Вот пример:
;---в сегменте данных
PATH DB 'B:FILENAME.EXT',0 ;путь к файлу
DATA_BUFFER DB 2000 DUP (?)
;---открываем файл с помощью функции "создания"
LEA DX,PATH ;DS:DX указывают на путь к файлу
MOV CX,0 ;атрибуты файлы (здесь обычные)
MOV AH,3CH ;номер функции
INT 21H ;открываем файл
JC OPEN_ERROR ;проверка на ошибку
MOV HANDLE,AX ;запоминаем номер файла
;---записываем в файл 1000 байтов
MOV AH,40H ;номер функции
MOV BX,HANDLE ;номер файла в BX
MOV CX,1000 ;число байт, которые надо записать
LEA DX,DATA_BUFFER ;DS:DX указывают на буфер данных
INT 21H ;записываем данные
JC OUTPUT_ERROR ;проверка на ошибки
CMP CX,2000 ;и их обработка
JNE FULL_DISK ;
Для добавления записей в последовательный файл надо открыть
файл с помощью функции 3DH прерывания 21H, помещая 1 в AL, если
программа будет только писать данные и 2, если программа будет и
читать и писать. Длина файла остается неизменной, хотя он будет
увеличиваться по мере добавления данных. Файловый указатель дол-
жен быть установлен на конец файла, иначе существующие данные
будут перезаписаны. Это выполняется функцией 42H прерывания 21H.
Поместите номер подфункции 2 в AL, для установки указателя на
конец файла, а номер файла поместите в BX. CX:DX указывают на
смещение относительно конца файла, начиная с которого будет
производиться запись, поэтому обнулите эти регистры. Затем выпол-
ните функцию установки указателя. При возврате установленный флаг
переноса индицирует ошибку, при этом в AX будет 1, если номер
подфункции в AL был неверен, и 6 - если неверно был указан номер
файла. После того как файловый указатель установлен операция
записи выполняется в точности как в предыдущем случае:
;---в сегменте данных
PATH DB 'B:FILENAME.EXT',0 ;путь к файлу
DATA_BUFFER DB 1000 DUP(?)
;---открываем файл
LEA DX,PATH ;DS:DX указывают на путь
MOV AL,1 ;код открытия только для записи
MOV AH,3DH ;номер функции
INT 21H ;открываем файл
JC OPEN_ERROR ;уход по ошибке
MOV HANDLE,AX ;сохраняем номер файла
;---установка файлового указателя на конец файла
MOV BX,AX ;номер файла в BX
MOV CX,0 ;CX:DX дают смещение относительно конца
MOV DX,0 ;
MOV AL,2 ;код для конца файла
MOV AH,42H ;функция установки указателя
INT 21H ;устанавливаем указатель
JC POINTER_ERROR ;проверка на ошибку
;---добавляем к файлу 300 байтов
MOV AH,40H ;номер функции
MOV BX,HANDLE ;номер файла в BX
MOV CX,300 ;число записываемых байтов
LEA DX,DATA_BUFFER ;DS:DX указывают на буфер данных
INT 21H ;добавляем данные
JC OUTPUT_ERROR ;проверка на ошибки
CMP CX,300 ;и их обработка
JNE FULL_DISK ;
5.4.4 Чтение из последовательных файлов.
Чтение из последовательного файла мало чем отличается от запи-
си в него, за исключением того, что процесс обратный. В Бейсике
данные берутся из файла и присваиваются отдельным переменным или
элементам массива данных. В языке ассемблера данные помещаются в
буфер, расположенный в памяти. В последнем случае данные пере-
даются по записям и программа должна сама выделять элементы дан-
ных, составляющие записи. В этом случае под записью понимается
порция данных, которая считывается из файла.
Высокий уровень.
Чтение последовательных файлов в Бейсике проще, чем их запись,
поскольку имеется только две возможности, как обращаться с ними,
в зависимости от того, какие символы в файле используются в ка-
честве ограничителей элементов данных. Оператор INPUT# распознает
запятые и кавычки, как разделители данных, так же как и пары
возврат каретки/перевод строки. Оператор LINE INPUT# распознает
только комбинации CR/LF, поэтому он может использоваться для
чтения целых строк текста, содержащих другие ограничители. Эта
возможность удобна при обработке текстов.
Для чтения трех элементов оператором INPUT#, сначала откройте
файл, как обсуждалось в [5.3.3] (например, OPEN "A:NEWSEQ" FOR
INPUT AS #1). Если файл был открыт под номером 1, то оператор
INPUT #1, X$, Y$, Z$ присвоит значение первых трех элементов
данных трем строковым переменным. При вводе числовых переменных,
например, INPUT #1, X, Y, Z необходимо, чтобы соответствующие
данные в файле были числовыми. Число с двойной точностью должно
считываться в переменную двойной точности, с тем чтобы она могла
хранить восемь байтов такого числа. Другой способ прочитать три
элемента данных состоит в размещении их в массиве:
100 DIM ITEM$(40) 'создаем массив строк из 40 элементов
110 FOR N = 0 TO 39 'для каждого элемента
120 INPUT #1, ITEM$(N) 'считываем его и помещаем в массив
130 NEXT '
Чтобы прочитать n-ный элемент последовательного файла программа
должна прочитать все предшествующие ему элементы. Hадо просто
создать цикл, в котором будут считываться элементы данных, но не
сохранять эти данные по мере их появления.
Оператор LINE INPUT# действует в основном аналогично оператору
INPUT#, за исключением того, что он может принимать только одну
переменную и это всегда строковая переменная. Переменная может
быть длиной до 254 символов и это максимально допустимый размер
строковых переменных в Бейсике. Пара возврат каретки/перевод
строки, содержащаяся в файле, включается в строку, возвращаемую
оператором LINE INPUT#. Это свойство позволяет обнаруживать конец
параграфа в текстовом файле.
Функция EOF (конец файла) может быть использована для опреде-
ления того, все ли элементы файла были прочитаны. Эта функция
возвращает -1, если файл исчерпан и 0 - в противном случае. Функ-
ции требуется номер файла, под которым он был открыт; например,
если был был открыт как #2, то X = EOF(2). В следующем примере
весь текстовый файл считывается в массив:
100 OPEN "TEXT.AAA" FOR INPUT AS #2 'открываем файл
110 DIM TEXT$(500) 'не более 500 строк
120 LINECOUNT = 0 'счетчик строк
130 LINE INPUT #2, TEXT$(LINECOUNT) 'получаем строку
140 IF EOF(2) THEN 170 'проверка на конец файла
150 LINECOUNT = LINECOUNT + 1 'увеличиваем счетчик
160 GOTO 130 'на следующую строку
170 ... 'файл прочитан
Оператор INPUT$ читает из последовательного файла указанное
число символов. Hа самой программе лежит забота о выделении от-
дельных элементов данных. Формат этого оператора для чтения 30
символов из файла #1 такой: S$ = INPUT$(30,#1). Хотя Вы можете
указывать число байт для чтения, необходимо чтобы это число не
превосходило 254, поскольку это максимальный размер строковой
переменной, в которую помещаются данные. INPUT$ полезен при пере-
даче массы данных в непрерывную область памяти. Hапример, в сле-
дующем примере делается дамп первых 200 байтов последовательного
файла в буфер монохромного дисплея, с тем чтобы они были выведены
на экран, включая управляющие коды:
100 OPEN "A:NEWFILE" FOR INPUT AS #1 'открываем файл
110 CLS: DEF SEG = &HB000 'указываем на буфер
120 FOR N = 0 TO 9 'получаем 10 групп
130 S$ = INPUT$(20,#1) 'по 20 байтов
140 FOR M = 1 TO 20 'берем каждый байт
150 POKE N*160 + M*2, ASC(MID$(S$,M,1) 'и помещаем его в буфер
160 NEXT M 'переход к следующему байту
170 NEXT N 'переход к следующей группе
Средний уровень.
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 ;посылаем в поле размера записи