5.4.5 Запись в файлы прямого доступа.

Error message

Notice: Undefined index: add term path in hansel_get_breadcrumbs() (line 524 of /data/sites/msdosworld.ru/www/sites/all/modules/hansel/hansel.module).

  Физически  файлы прямого доступа ничем не отличаются от после-
довательных файлов, они  отличаются  только режимом доступа. Файл


прямого  доступа предполагает, что его данные организованы в виде
записей фиксированной длины, таким образом положение каждой запи-
си может быть вычислено (в последовательных файлах 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                     'иначе закрываем файл

   Средний уровень.

   Как и все другие операции с файлами в MS DOS имеется два мето-
да записи в файл прямого доступа, один с использованием управляю-


щего блока файла, а другой с  помощью  дескриптора файла. В обоих
случаях  Вы должны создать буфер обмена данными, размер  которого
должен быть не меньше, чем размер записи.

Метод управляющего блока файла:
   Откройте управляющий блок  файла с помощью функции 0FH и пусть
DS:DX  указывают на него.  После того как файл  открыт  поместите
номер записи для  прямого  доступа  в поле записи прямого доступа
FCB.  Затем вызовите функцию 22H прерывания 21H, которая  пердаст
данные из DTA в файловый буфер, созданный при создании FCB.  Дан-
ные могут не быть немедленно записаны на диск, если размер записи
меньше чем размер буфера.  Реальная запись на диск будет происхо-
дить тогда, когда очередной вызов функции 22H заполнит буфер.
   При  возврате из функции 22H AL будет содержать 00, если обмен
прошел успешно. В противном случае в нем будет 1, если не хватает
пространства на диске и 2 - если область переноса мала для  того,
чтобы записать одну запись (т.е.  если размер буфера, установлен-
ный системой меньше, чем тот, который указан в FCB).

;---в сегменте данных
FCB       DB   1, 'NEWDATA    ', 25 DUP (0)
DTA       DB   256 DUP (?)

;---открываем файл и устанавливаем поля FCB
   MOV  AH,0FH          ;номер функции
   LEA  DX,FCB          ;DS:DX указывают на FCB
   MOV  BX,DX           ;копируем смещение для FCB
   INT  21H             ;открываем файл
   MOV  AX,256          ;размер записи
   MOV  [BX]+14,AX      ;помещаем в поле размера записи
   MOV  AX,233          ;номер записи
   MOV  [BX]+33,AX      ;помещаем в поле номера записи
   MOV  AX,0            ;обнуляем старший байт этого слова
   MOV  [BX]+35,AX      ;
;---перенос данных из DTA в файл
   MOV  AH,22H          ;номер функции записи с прямым доступом
   LEA  DX,FCB          ;DS:DX указывают на FCB
   INT  21H             ;записываем данные
   CMP  AL,0            ;проверка на ошибку
   JNE  WRITE_ERROR     ;

;---позднее, закрываем файл
   LEA  DX,FCB          ;DS:DX указывают на FCB
   MOV  AH,10H          ;функция закрытия файла
   INT  21H             ;закрываем файл
   CMP  AL,0FFH         ;проверка на ошибку
   JE   CLOSE_ERROR     ;

   Часто  программа работает сразу с набором записей прямого дос-
тупа, передавая их в память и из памяти  как единое целое. MS DOS
предоставляет  специальную  функцию для этого  при  использовании
метода FCB, называемую запись блока  с прямым доступом. Это функ-
ция 28H прерывания 21H.  При входе DS:DX должны указывать на отк-


рытый FCB, в  котором  поле  записи  прямого  доступа должно быть
равно номеру первой из записываемых записей набора.  Эта  функция
совершенно  аналогична  вышеприведенному  примеру.   Единственное
отличие  (кроме  номера функции) состоит в том, что в  CX  должно
быть указано число  записей  в  блоке  (не  путайте эти "блоки" с
блоками по 128 записей, с помощью которых система находит требуе-
мую запись - программа может  читать любое число записей, начиная
с любого места).

   В CX возвращается число реально прочитанных записей.  AL будет
содержать 0, если все записи  успешно  записаны, 1 - если не хва-
тает  пространства  на диске, при этом не будет записана ни  одна
запись. В отличии от функции 22H эта функция автоматически увели-
чивает поля текущей записи, текущего блока и записи прямого  дос-
тупа в FCB, так что они будут  указывать  на запись, следующую за
последней  прочитанной.   Отметим, что если при  выполнении  этой
функции установить CX = 0,  то  размер  файла  будет установлен в
соответствии с числом записей, равным полю записи прямого  досту-
па, и таким образом можно резервировать для файла дисковое прост-
ранство.

Метод дескриптора файлов:
   При использовании для доступа метода дескриптора файлов систе-
ма не различает  последовательные  файлы и файлы прямого доступа.
Ваша программа должна вычислить позицию в файле, с которой  начи-
нается требуемая запись, и  установить на нее файловый указатель.
Файловый указатель позиционируется с помощью функции 42H прерыва-
ния 21H. Поместите номер файла  в  BX, а смещение в файле в CX:DX
(CX будет содержать старший байт значения).  Затем поместите в AL
кодовый номер от 0 до 2. При AL  =  0, указатель будет установлен
со смещением CX:DX байтов относительно начала файла; при AL =  1,
указатель будет установлен со  смещением CX:DX относительно теку-
щей  позиции, а при AL = 2, указатель будет установлен со  смеще-
нием CX:DX относительно  конца  файла  (т.е.   таким образом файл
будет расширен).  Отрицательные числа недопустимы в качестве сме-
щений.  При возврате DX:AX будут содержать новое положение указа-
теля (старший байт в DX).  Если устанавливается флаг переноса, то
произошла ошибка. В этом случае AX будет содержать 1, если указан
неверный код в AL и 6 - если указан неверный номер файла.
   После  позиционирования  файлового  указателя  запись  прямого
доступа записывается с помощью той же функции 40H прерывания 21H,
которая  использовалась для записи в последовательный файл.   При
входе BX содержит номер файла, а CX  - число байтов, которое надо
записать.  При возврате AX будет содержать число реально записан-
ных байтов. Если  оно  отличается  от  числа помещенного в CX, то
вероятно диск полон (см. [5.1.4]).  Как обычно, при возникновении
ошибки устанавливается  флаг  переноса.   В  этом случае AX будет
содержать  5  при  ошибке накопителя и 6 - если  указан  неверный
номер файла.
   Файловый указатель играет ту же  роль для образа файла на дис-
ке,  что DTA для образа файла в памяти.  Он может сдвигаться  как
угодно для доступа к различным частям файла.  Будьте внимательны,
манипулируя файловым указателем при работе с фалом прямого досту-


па, содержимое любого поля любой записи может быть сразу прочита-
но с диска и помещено в требуемое место в памяти.

;---в сегменте данных
HANDLE        DW    ?           ;номер файла
FILEPATH      DB    'A:NEWDATA',0   ;строка пути к файлу
REC_BUFFER    DB    30 DUP (?)  ;буфер выводимых записей

;---открываем файл
   MOV  AH,3DH               ;номер функции
   MOV  AL,1                 ;код открытия для записи
   LEA  DX,FILEPATH          ;DS:DX указывают на путь
   INT  21H                  ;открываем файл
   JC   OPEN_ERROR           ;проверка на ошибку
   MOV  HANDLE,AX            ;сохраняем номер файла

;---вычисляем позицию записи и устанавливаем файловый указатель
   MOV  AX,30                ;размер записи 30 байтов
   MOV  CX,54                ;номер записи #54 (55-я запись)
   MUL  CX                   ;теперь смещение для нее в DX:AX
   MOV  CX,DX                ;помещаем старшее слово в DX
   MOV  DX,AX                ;помещаем младшее слово в CX
   MOV  AL,0                 ;устанавливаем указатель на начало
   MOV  AH,42H               ;функция установки указателя
   MOV  BX,HANDLE            ;номер файла
   INT  21H                  ;устанавливаем указатель
   JC   POINTER_ERROR        ;проверка на ошибку
;---пишем запись с прямым доступом
   MOV  AH,40H               ;номер функции
   MOV  BX,HANDLE            ;номер файла
   MOV  CX,30                ;размер записи
   LEA  DX,REC_BUFFER        ;DS:DX указывают на буфер
   INT  21H                  ;пишем запись
   JC   WRITE_ERROR          ;проверка на ошибку

   В отличии от метода FCB метод дескриптора файлов не предостав-
ляет специальной функции для записи  блока записей прямого досту-
па. Однако Вашей программе необходимо только вычислить количество
байтов, составляющих блок записей, которое должно быть записано.
 

Вы находитесь в разделе: 

Добавить коментарий