ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 04.07.2020
Просмотров: 3147
Скачиваний: 1
100 DIM ITEM$(40) 'создаем массив строк из 40 элементов
110 FOR N = 0 TO 39 'для каждого элемента
120 INPUT #1, ITEM$(N) 'считываем его и помещаем в массив
130 NEXT '
Чтобы прочитать n-ный элемент последовательного файла программа
должна прочитать все предшествующие ему элементы. Надо просто
создать цикл, в котором будут считываться элементы данных, но не
сохранять эти данные по мере их появления.
Оператор 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$ читает из последовательного файла указанное
число символов. На самой программе лежит забота о выделении от-
дельных элементов данных. Формат этого оператора для чтения 30
символов из файла #1 такой: S$ = INPUT$(30,#1). Хотя Вы можете
указывать число байт для чтения, необходимо чтобы это число не
превосходило 254, поскольку это максимальный размер строковой
переменной, в которую помещаются данные. INPUT$ полезен при пере-
даче массы данных в непрерывную область памяти. Например, в сле-
дующем примере делается дамп первых 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 'переход к следующей группе
Средний уровень.
Как и для всех файловых операций 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 ;обработка ошибки
5.4.5 Запись в файлы прямого доступа.
Физически файлы прямого доступа ничем не отличаются от после-
довательных файлов, они отличаются только режимом доступа. Файл
прямого доступа предполагает, что его данные организованы в виде
записей фиксированной длины, таким образом положение каждой запи-
си может быть вычислено (в последовательных файлах n-ный элемент
ищется путем подсчета разделителей между элементами, начиная с
начала файла). Операционная система автоматически выполняет эти
вычтсления. Однако любая программа может выполнять эту работу
сама, устанавливая файловый указатель на нужную позицию и считы-
вая последовательно такое число байтов, которое образует запись.
Высокий уровень.
В [5.3.3] объяснен формат открытия файдов прямого доступа в
Бейсике. В отличии от последовательного файла, файл прямого дос-
тупа может читаться и записываться в одно и то же время, без
закрытия и повторного его открытия. Оператор OPEN завершается
числом, дающим размер записи файла. Например, OPEN "R", 1, "NEW-
DATA", 20 устанавливает для файла NEWDATA размер записи в 20 байт
(при этом файл открывается как файл #1).
После того как файл открыт, его записи могут быть разбиты на
составляющие переменные с помощью оператора FIELD. Оператор FIELD
указывает сколько байтов записи отводится под каждую переменную.
Например, запись длиной 20 байт может быть разбита оператором
FIELD 1, 14 AS LASTNAME$, 2 AS DEPOSIT$, 4 AS ACCTNUM$. В этом
операторе первая цифра 1 указывает, что данный оператор FIELD
описывает разбиение записи для файла, открытого под номером #1.
Данные располагаются в записи точно в том порядке, в каком они
описаны в операторе FIELD. Опреаторы RSET и LSET сдвигают данные
в полях, выравнивая их по правому (RSET) или левому (LSET) краю и
заполняя остающиеся пустые места пробелами. Например, для того,
чтобы вставить фамилию "SMITH" в 14-байтное поле с именем LASTNA-
ME$, надо записать RSET LASTNAME$ = "SMITH", или если переменной
N$ было присвоено значение "SMITH", то RSET LASTNAME$ = N$. Вмес-
то RSET может быть использовано LSET. Когда впоследствии данные
считываются из поля в переменную, то переменной присваиваются все
14 байтов. При использовании RSET программа удалит все лишние
пробелы в начале строковой переменной, однако если будет исполь-
зоваться LSET, то пробелы будут удаляться справа.
Отметим, что все имена переменных в операторе FIELD относятся
к строковым переменным. В файлах прямого доступа Бейсик рассмат-
ривает все переменные - включая числовые - как строковые. Число-
вая переменная должна быть преобразована в специальный вид, преж-
де чем ее значение может быть присвоено полю, а когда она затем
считывается из поля то необходимо обратное преобразование. Слово
преобразование стоило бы заключить в кавычки, поскольку Бейсик на
самом деле не меняет способ представления числа в памяти; он
просто обрабатывает число особым образом. Числовые поля требуют
двух байтов для целых чисел, четырех байтов - для чисел с обычной
точностью и восьми байтов - для чисел с двойной точностью. В
точности такое же число байт требуется для представления этих
чисел в памяти. Для преобразования их в строковую форму надо
использовать функции MKI$, MKS$ и MKD$, которые осуществляют
преобразование число-строка для целых, вещественных и чисел с
двойной точностью, соответственно. Обычно эти функции комбини-
руются с операторами RSET или LSET, например, RSET = ACCTNUM$ =
MKI$(X), где X - целая переменная, если полю ACCTNUM$ было отве-
дено два байта в операторе FIELD.
После того как поля заполнены операторами RSET и LSET, запись
записывается на диск с помощью оператора PUT#. PUT #1, 245 поме-
щает данные в запись номер 245, файла открытого под номером #1.
Номер записи может быть опущен, в этом случае данные записываются
в запись с номером на единицу больше, чем номер последней запи-
санной записи (начиная с записи 1). Записывается вся запись цели-