Страница 37 из 41
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 'иначе закрываем файл
|