Файл: jourdain_spravochnik_programmista.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 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). Записывается вся запись цели-