Справочник программиста на персональном компьютере фирмы IBM. Дисковые накопители - Запись в файлы прямого доступа

ОГЛАВЛЕНИЕ

     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). Записывается вся запись цели-
ком,  даже если не все поля были заполнены данными.  Отметим, что
поля буфера не очищаются  при  выполении  операции  PUT,  поэтому
элементы данных, такие как текущая дата, могут помещаться в буфер
только один раз, а затем они будут  записаны во все записи, кото-
рые будут записываться в течение данной сессии. Функция LOC возв-
ращает номер последней  записанной  в  файл записи. Если файл был
открыт под номером #3, то напишите X = LOC(3).
   Функция LOF (длина файла) возвращает длину файла в байтах. Для
определения числа записей,  содержащихся  в файле, надо разделить
это значение на длину записи.  Добавление 1 к этому значению дает
номер записи, который надо  использовать,  чтобы добавить к файлу
новые  записи.  Если файл был открыт под номером #2, а длина  его
записей равна 32 байтам, то  требуемое  значение  вычисляется как
RECORDNUM = LOF(2)/32 + 1.
   В следующем примере файл прямого доступа открывается с  длиной
записи 24 байта, причем запись разбита на три переменные. Пользо-
ватель  программы  запрашивается о содержимом всех трех полей,  а
когда все они введены, то  запись  добавляется  к файлу. В строке
120 вычисляется начальный номер записи. Отметим, что данные могут
не записываться физически на диск  каждый раз при выполнении опе-
ратора PUT. В выходном буфере могут накапливаться несколько запи-
сей, прежде чем это будет сделано.

100 OPEN "R", 1, "A:NEWDATA.DAT", 24  'открываем файл
110 FIELD 1, 18 AS LASTNAME$, 2 AS AGE$, 4 AS WEIGHT
120 R = LOF(1)/24 + 1         'номер последней записи + 1
130 CLS                       'чистим экран
140 INPUT "Enter name:",N$    'получаем имя (строка)
150 INPUT "Enter age:",A%     'получаем возраст (целое)
160 INPUT "Enter weight:",W!  'получаем вес (вещественное)
170 RSET LASTNAME$ = N$       'помещаем в поле имя
180 RSET AGE$ = MKI$(A%)      'помещаем в поле возраст
190 RSET WEIGHT$ = MKS$(W!)   'помещаем в поле вес
200 PUT #1, R                 'записываем запись
210 R = R + 1                 'увеличиваем счетчик
220 PRINT: PRINT "Do another (y/n)?"  'запрос пользователя
230 C$ = INKEY$: IF C$ = "" THEN 220  'ожидаем ответа
240 IF C$ = "y" THEN CLS: GOTO 130    'если да, то на начало
250 CLOSE                     'иначе закрываем файл