<<
>>

Буферизованный и произвольный доступ к файлам

Программа InFilBuf.s, представленная в листинге В.8, являет собой пример произвольного файлового ввода-вывода. Она допускает, что файл состоит из произвольного числа символьных строк, каждая из которых потенциально может отличаться по длине от других.
Сначала эта программа считывает файл и формирует таблицу, в которой запись п отражает положение начала строки п в файле. Впоследствии можно запросить конкретную символьную строку, отыскать запись для нее в таблице и считать с помощью системных вызовов 1 seek и read. Имя файла при стандартном вводе указывается в первой вводимой строке. Программа состоит из нескольких относительно независимых кодовых фрагментов, которые можно адаптировать для иных целей.

Листинг В.8. Программа, реализующая буферизованный и произвольный доступ к файлу
БиВ АХ.СХ ! 31
ХСНв 51,01 ! 32
ЗТОБ ! 33
ХСНв 51,01 ! 34
СМР сх.о ! 35
JNE 2Ь ! 36
ЛР 1Ь ! 37
МОУ 5Р.ВР ! 38
Р115Н Ипе1п ! 39
Р1БН егтеББ ! 40
рли РШтТ ! 41
5У5 ! 42
РЛИ ЕХ1Т ! 43
РЛИ ЕХ1Т ! 44
БУЗ ! 45
САН деЕпит ! 46
СМР АХ,0 ! 47
ЛЕ 8Г ! 48
МОУ ВХ.(сигИп) ! 49
СМР ВХ,0 ! 50
ЛЕ 7Г ! 51
СМР ВХ.СсоипЬ) ! 52
00 7Г ! 53
ЗН1_ ВХ.1 ! 54
МОУ АХ,11пЬ-2(ВХ) ! 55
МОУ СХ.ИгМВХ) ! 56
рли 0 ! 57
рли 0 ! 58
РЛИ АХ ! 59
РЛИ (Шс^) ! 60
РЛИ 1_5ЕЕК ! 61
ЗУБ ! 62
511В СХ.АХ ! 63
рли СХ ! 64
РЛИ ЬиГ ! 65
рли (Шск^) ! 66
РЛН 1ЛА0 ! 67
БУЗ ! 68
АОО 5Р,4 ! 69
РЛН 1 ! 70
РЛИ 1л1Р1ТЕ ! 71
ЗУЗ ! 72
АОО 5Р.14 ! 73
ЛР ЗЬ ! 74
Р115Н эсапегг ! 75
рли Р1ШТР ! 76
ЗУЗ ! 77
АОО 5Р,4 ! 78
ЗМР ЗЬ ! 79
рли 0 ! 80
РЛИ ЕХ1Т ! 81
ЗУЗ ! 82
1 ЬиС: ! 83
РЛН ЬиСэ-! г ! 84
РиЗН ЬиГ ! 85
РиЗН (Шс^) ! 86
РиЗН 1ЛА0 ! 87
ЗУЗ ! 88
АОО ЗР,8 ! 89
MOV CX.AX ! 90
ADD BX.CX ! 91
MOV Dl.buf ! 92
RET ! 93
getnum: ! 94
MOV DI,1inein ! 95
PUSH GETCHAR ! 96
1: SYS ! 97
CMPB AL.'\n' ! 98
JL 9b ! 99
JE If ! 100
STOSB ! 101
JMP lb ! 102
1: MOVB (DI).' * ! 103
PUSH curl in ! 104
PUSH numfmt ! 105
PUSH 1inein ! 106
PUSH SSCANF ! 107
SYS ! 108
ADD SP.10 ! 109
RET ! 110
.SECT .DATA ! Ill
errmess: ! 112
.ASCIZ "Open %s failed\n" ! 113
numfmt: .ASCIZ ”%d" ! 114
scanerr: ! 115
.ASCIZ "Type a number.\n" ! 116
.ALIGN2 ! 117
.SECT .BSS ! 118
1inein: .SPACE 80 ! 119
fildes: .SPACE2 ! 120
linh: .SPACE 8192 ! 121
curl in: .SPACE4 ! 122
buf: .SPACE bufsiz+2 ! 123
count: .SPACE2 ! 124

В первых пяти строках кода определяются номера системных вызовов и размер буфера, а указатель базы, как обычно, настраивается на вершину стека. В строках 6-13 из стандартного ввода считывается имя файла, а затем оно сохраняется в символьной строке с меткой 1 inein.

Если имя файла не закрыто новой строкой, выводится сообщение об ошибке, а процесс заканчивается с ненулевым состоянием.
Все эти действия отражены в строках 38-45. Обратите внимание, что адрес имени файла помещается в стек в строке 39, адрес сообщения об ошибке — в строке 40. Само сообщение об ошибке (представленное в строке ИЗ) представляет собой запрос на строку $s в формате PRINTF. Здесь же выполняется вставка содержимого строки 1 inein.

В случае успешного копирования имени файла его открытие производится в строках 14-20. Если вызов open завершается с ошибкой, возвращаемое значение становится отрицательным, и для отображения сообщения об ошибке производится переход к метке 9 в строке 28. Если вызов проходит успешно, возвращаемым значением является дескриптор файла, который сохраняется в переменной f i 1 des. Этот дескриптор понадобится при последующем выполнении вызовов read и 1 seek.

Далее файл считывается блоками по 512 байт, каждый из которых сохраняется в буфере buf. На самом деле под буфер выделяется на два байта больше необходимого объема (512 байт), но сделано это лишь для того, чтобы показать способ размещения символической константы и целого числа в одном выражении (строка 123). Аналогичным образом, в строке 21 в регистр SI загружается адрес следующего элемента массива linh, в результате на дне массива остается машинное слово с нулевым значением. Регистр ВХ получает адрес файла первого непрочитанного символа файла, а значит, в строке 22 перед первым наполнением буфера он инициализируется нулем.

За наполнение буфера отвечает подпрограмма fill buf, размещенная в строках 83-93. После введения в стек аргументов read делается запрос на системный вызов, который помещает число фактически считанных символов в регистр АХ. Это число копируется в СХ, и впоследствии по значению этого регистра можно будет узнать число оставшихся в буфере символов. Положение в файле первого непрочитанного символа хранится в регистре ВХ, и в строке 91 значение СХ прибавляется к значению ВХ. В строке 92 дно буфера помещается в DI; таким образом, осуществляется подготовка к просмотру буфера на предмет следующего символа новой строки.

После возврата из fill buf в строке 24 проводится проверка того, были ли какие-либо символы фактически считаны.

При отрицательном ответе происходит переход из цикла чтения с буферизацией ко второй части программы в строке 25.

После этого начинается просмотр буфера. Символ \п загружается в регистр AL в строке 26, а уже в следующей строке это значение просматривается в цикле REP SCASB и сравнивается с буферизованными символами. Выход из цикла может произойти в двух случаях: когда в регистре СХ оказывается нулевое значение или когда просматриваемый символ оказывается символом новой строки. При установленном нулевом флаге последним просмотренным символом оказывается \п, а положения в файле текущего символа (расположенного после перевода строки) сохраняется в массиве linh. Далее происходит приращение счетчика, а положение в файле определяется по значению ВХ и числу символов, оставшихся в СХ (строки 29-31 кода). В строках 32-34 выполняется сохранение, но так как для команды ST0S целевым адресом является не регистр SI, а регистр DI, перед и после вызова команды ST0S эти регистры меняются местами. В строках 35-37 производится проверка оставшихся в буфере данных, после чего в зависимости от значения СХ выполняется переход.

По достижении конца файла в нашем распоряжении оказывается полный список положений в файле начальных элементов строк. Так как массив linh начинается с нулевого слова, нам известно, что первая строка начинается с адреса О, следующая строка находится в положении linh + 2, и т. д. Размер строки п можно вычислить путем вычитания начального адреса строки п из начального адреса строки n + 1.

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

Эта часть программы начинается с вызова подпрограммы getnum (строка 46 кода).

Она считывает символьную строку из стандартного ввода и сохраняет в буфере 1 inein (строки 95-103 кода). Далее подготавливается вызов SSCANF. Принимая во внимание обратный порядок следования аргументов, в стек сначала помещается адрес буфера curl in, где можно разместить целочисленное значение, затем адрес форматной строки для целочисленного представления numfmt, и, наконец, адрес буфера 1 inein, в котором содержится число в десятичном представлении. Если это возможно, системная подпрограмма SSCANF помещает двоичное значение в curl in. В случае ошибки она возвращает нулевое значение АХ. Проверка возвращаемого значения проводится в строке 48; при ошибке программа генерирует сообщение об ошибке посредством метки 8.

Если подпрограмма getnum возвращает действительное целочисленное значение в curl in, оно сначала копируется в ВХ. Далее это значение проверяется на предмет принадлежности к допустимому диапазону (строки 49-53 кода). Если обнаруживается, что номер строки выходит за пределы этого диапазона, происходит выход (EXIT).

Далее необходимо определить конечное положение данной строки в файле и число считываемых файлов; с этой целью значение ВХ умножается на 2 посредством сдвига влево (SHL). В строке 55 положение текущей символьной строки в файле копируется в регистр АХ. Затем положение следующей символьной строки помещается в регистр СХ, и на его основе вычисляется число байтов в текущей строке.

Для произвольного чтения данных из файла применяется вызов 1 seek; он устанавливает смещение к байту, который предполагается прочесть в следующую очередь. Подпрограмма 1 seek выполняется относительно начала файла, и в этой связи в строке 57 в стек помещается нулевой аргумент. Следующим аргументом является смещение в файле. По определению этот аргумент является длинным (32-разрядным) целым, поэтому сначала в стек вводится пулевое слово, а затем — значение АХ (строки 58 и 59 кода); таким образом формируется 32-разряд- ное целочисленное значение. Далее в строке 62 в стек отправляются дескриптор файла и код LSEEK, а также выполняется вызов. Возвращаемое значение LSEEK определяет текущее положение в файле, а найти его можно в комбинации регистров DX : АХ. Если число умещается в рамки машинного слова (а размер файла не превышает 65 536 байт, по-другому быть и не может), адрес помещается в АХ; следовательно, если вычесть значение этого регистра из СХ (строка 63), мы получим число байтов, которые необходимо прочесть для помещения строки в буфер.

Все остальное очень просто. В строках 64-68 строка считывается из файла, а затем при помощи дескриптора 1 файла в строках 70-72 она записывается в файл стандартного вывода. Следует иметь в виду, что после частичной очистки стека, которая выполняется в строке 69, значения счетчика и буфера в нем остаются. Наконец, в строке 73, указатель стека сбрасывается полностью, после чего осуществляются обратный переход к метке 3 и очередной вызов getnum.

<< | >>
Источник: Таненбаум Э.. Архитектура компьютера. 5-е изд. 2007

Еще по теме Буферизованный и произвольный доступ к файлам:

  1. ВОСПОМИНАНИЕ ПРОИЗВОЛЬНОЕ
  2. ЗАПОМИНАНИЕ ПРОИЗВОЛЬНОЕ
  3. ВНИМАНИЕ ПРОИЗВОЛЬНОЕ
  4. ДВИЖЕНИЕ ПРОИЗВОЛЬНОЕ
  5. ДВИЖЕНИЕ ПРОИЗВОЛЬНОЕ: ФОРМИРОВАНИЕ
  6. ВОСПРОИЗВЕДЕНИЕ ПРОИЗВОЛЬНОЕ
  7. 3. Доступ к источникам информации.
  8. Прямой доступ к информации и предузнавание
  9. Непосредственный доступ и предсказания
  10. § 6. Равный доступ к государственной службе
  11. 2.1.4. Классификация информации по доступу к ней
  12. Ключ доступен каждому.
  13. Прямой доступ к информации (на основе книг Барбары Энн Бреннан).
  14. Метод Ключ – защита от стресса и доступ к управлению внутренними ресурсами
  15. Принцип обеспечения потерпевшим права на доступ к правосудию и возмещение причиненного преступлением вреда
  16. Статья 200. Незаконные действия с документами на перевод, платежными карточками и иными средствами доступа к банковским счетам, оборудованием для их изготовления
  17. 15.6. Порядок доступа к Архивным фондам и использования архивных документов
  18. Статья 361-2. Несанкционированные сбыт или распространение информации с ограниченным доступом, которая сохраняется в электронно-вычислительных машинах (компьютерах), автоматизированных системах, компьютерных сетях или на носителях такой информации
  19. Статья 362. Несанкционированные действия с информацией, обрабатывается в электронно-вычислительных машинах (компьютерах), автоматизированных системах, компьютерных сетях или сохраняется на носителях такой информации, совершенные лицом, имеет право доступа к ней