Краткие теоретические сведения. 2.1 Файловая система Турбо-Пролога и переадресация каналов ввода и вывода
2.1 Файловая система Турбо-Пролога и переадресация каналов ввода и вывода
Составными частями компьютера являются устройства ввода/вывода, используемые программой на Турбо-Прологе во время ее работы. Например, для программы работающей в интерактивном режиме, с клавиатуры в компьютер вводятся целевые утверждения. Программа выводит на экран монитора результаты. Однако консоль является не единственным физическим устройством, которое может участвовать в работе программы. Большинство современных языков программирования высокого уровня обеспечивают интерфейс с операционной системой, который позволяет работать с различными физическими устройствами. Турбо-Пролог обеспечивает эту возможность путем поддержания предикатов, осуществляющих назначение каналам ввода и вывода различных устройств ввода\вывода или файлов, что позволяет вводить и выводить информацию с соответствующих устройств или файлов. Встроенный предикат Турбо-Пролога ReadDevice (<имя устройства или логического файла>) позволяет переадресовывать канал ввода на указанное устройство ввода или файл. Аналогично встроенный предикат WriteDevice (<имя устройства или логического файла>) осуществляет переадресацию каналов вывода информации на указанное устройство вывода или файл.
Пример.
Предикаты
readdeviсе(com1).
readdeviсе(dat.dat).
настраивают канал ввода на коммуникационный порт corn1 и логический файл dat.dat соответственно, а предикаты
writedevice(screen).
writedevice(printer)
настраивают канал вывода на экран и принтер.
В Турбо-Прологе по умолчанию каналу ввода назначается устройство ввода - клавиатура, а каналу вывода - экран монитора. Если эти назначения не устраивают,то необходимо воспользоваться предикатами переадресации каналов ввода и вывода. Чтобы иметь доступ к файлу, его надо открыть. Файл может быть открыт четырьмя способами:
- для чтения используется предикат
openread (<имя физического файла>, <имя логического файла>);
- для записи используется и предикат
openwrite (<имя физического файла>, <имя логического файла>);
- для добавления используется предикат
openappend (<имя физического файла>, <имя логического файла>);
- для модификации используется предикат
openmodify(<имя физического файла>, <имя логического файла>)
Файл, открытый для любых действий, кроме чтения, должен быть закрыт, когда действия закончены, в противном случае внесенные изменения могут быть утеряны. Для закрытия файла используется встроенный предикат closefile(<имя логического файла>).
Одновременно можно открыть несколько файлов, и канал ввода/вывода можно быстро переадресовать между открытыми файлами. Больше времени требуется на то, чтобы открыть и закрыть файл, чем на переадресацию канала ввода/вывода между ними.
После того, как файл открыт, Турбо-Пролог связывает имя логического файла с именем физического файла. Имя физического' файла - это имя файла в операционной системе (OC). Логическое имя файла Турбо-Пролог использует при переадресации канала ввода/вывода, Имя логического файла есть идентификатор и должно начинаться с маленькой буквы и объявлено в разделе domains после ключевого слова file. Объявление одного имени логического файла выглядит как domains
file<имя логического файла>,
а нескольких
domains
file<имя логического файла 1>;<имя логического файла 2>...
В программе может быть только одно поле объявления файлов - file.
Турбо-Пролог автоматически заранее объявляет четыре имени:
- printer (относится к параллельно-печатающему порту);
- screen (относится к экрану монитора); .
- keyboard (относится к клавиатуре);
- com1 (относится к последовательному порту связи).
Эти имена не должны появляться при объявлении файлов.
2.2 Организация обработки файлов
В наиболее общем виде запись информации в файл может быть представлена следующей последовательностью действий:
openwrite(datafile, ''Dat.dat''),
writedevice(datafile)
<предикаты записи в файл>
<любые предикаты>
closefile(datafile).
Для чтения информации из файла может служить следующий фрагмент:
opendevice(datafile, ''Dat.dat''),
readdeviсе(datafile)
<предикаты чтения в файл>
<любые предикаты>
closefile(datafile).
Кроме записи и чтения информации в файл, в Турбо-Прологе возможно выполнение модификации уже существующего файла (и запись, и чтение) и добавление информации в конец файла. В наиболее общем виде эти действия можно представить следующими фрагментами.
Модификация файла:
openmodify (datafile,'Dat.dat''),
readdeviсе(datafile),
writedevice(datafile),
<предикаты для выборочного чтения и записи в файл>
<любые предикаты>
closefile(datafile).
Добавление в файл:
openappend (datafile,'Dat.dat''),
writedevice(datafile),
<предикаты для дозаписи в файл>
<любые предикаты>
closefile(datafile).
2.3 Предикаты Турбо-Пролога для работы с файлами
Для работы с файлами в системе Турбо-Пролог имеются следующие предикаты.
openread(<имя физического файла>, <имя логического файла>);
Здесь физический файл открывается для чтения. Если файл не найден, то предикат не выполняется (не успешен). Если имя физического файла является недопустимым, то сообщается об ошибке.
openwrite(<имя физического файла>, <имя логического файла>);
Физический файл открыт для записи. Если файл существует, то он очищается. Если нет он создается и заносится в текущий каталог ОС.
openappend(<имя физического файла>, <имя логического файла>)
Физический файл открыт для добавления информации в конец файла. Если файл не найден, то выводится сообщение об ошибке.
openmodify(<имя физического файла>, <имя логического файла>)
Физический файл открыт для чтения и записи. Предикат openmodify может использоваться со стандартным предикатом filepos для обновления файлов прямого доступа.
closefile(<имя логического файла>).
Предикат закрывает файл, т.е. разрывает связь логического файла с физическим, Даже если файл не был открыт, ошибки не будет,
readdeviсе (<имя устройства или логического файла>).
Переадресовывает канал - ввода на указанное устройство или файл, открывая их для чтения. Если имя логического файла было свободно, то оно связывается с текущим назначением канала ввода.
writedevice (<имя устройства или логического файла>).
Переадресовывает канал вывода на указанное устройство или файл, открывая их для записи или добавления. Если имя логического файла было свободно, то оно связывается с текущим назначением канала вывода.
exitsfile(<имя физического файла>).
Предикат успешен, если файл с указанным именем существует.
eof(<имя логического файла>).
Предикат успешен, если достигнут конец файла, и не успешен в противном случае.
В Турбо-Прологе имеется ряд других стандартных предикатов для работы с файлами. Описание этих предикатов приводится в соответствующей литературе по Турбо-Прологу.
2.4 Примеры организации файловой обработки
2.4.1 Вывод информации, вводимой с клавиатуры на экран дисплеи и файл на диске
domains
file=dateFile
predicates
check(string)
wr_linеs.
clauses
wr_lines:- readln(X),
write(Х), nl,
writedevice(datafile),
write(X), nl,
writedevice(screen),
check(X).
wr_linеs.
check("end"):-!.
check(_):-fail.
goal
openwrite(datafile,''Dat.dat''),
wr lines,
closefile(datafile).
Обрабатываемая информация вводится с клавиатуры построчно: Последняя строка - end.
2.4.2 Чтение данных из файла и вывод их на экран
domains
file=datafile
predicates
read_write.
goal
openread(datafile,'Dat.dat'')),
readdeviсе(datafile),
read_write,
closefile(datafile).
clauses
read_write:-not(eof(datafile)),
readln(Line),
write(Line),nl,
read_write.
read_write.
2.5 Файлы прямого доступа
Файл прямого доступа - это файл, позволяющий работать с произвольной записью в нем без предварительного чтения предыдущих записей. Файлы, где нельзя без этого обойтись. называются файлами последовательного доступа. Файлы, рассматриваемые до сих пор, были именно таковыми.
В файлах прямого доступа все записи имеют одинаковую длину. Указатель перемещается по позициям кратным длине записи, он указывает всегда на начало очередной записи. Турбо-Пролог содержит встроенный предикат, который удобен для работы с файлами прямого доступа: filepos.
filepos (<имя логического файла>, <позиция в файле>, <режим>).
<позиция в файле> указывает позицию, из которой будет считан или в которую будет записан символ.
<режим> может иметь одно из трех значений 0, 1, 2. Эти значения определяют, как будет ориентировано значение аргумента.
<позиция в файле> определяется по таблице 3.
Таблица 3
Режим | Действие системы |
Смещение берется относительно начала файла | |
Смещение берется относительно текущей позиции | |
Смещение берется относительно конца файла |
Например:
- filepos(f,100,0)
указатель передвигается к 100-й позиции от начала файла;
- filepos (f,100,1)
указатель смещается на 100 позиций вправо относительно текущей позиции файла;
- filepos(f,-100,1)
указатель смещается на 100 позиций влево относительно текущей позиции файла;
- filepos(f,-100,2) указатель сдвигается на 100 позиций влево относительно конца файла.
Предикат filepos может изменить позицию чтения и записи файла, который был открыт по openmodify. Предикат filepos может возвращать текущую файловую позицию, если переменная <позиция в файле> не связана и <режим> = 0.
Примечание - Начальная позиция файла - нулевая
2.6 Пример обработки файла прямого доступа
Работа с файлами прямого доступа требует знания структуры этого файла. Нужно знать, к примеру, длину каждой записи файла, число записей, начальную позицию первой записи.
Приведем программу чтения n-ой записи из файла прямого доступа. Номер интересуемой записи вводится по запросу с клавиатуры. Предполагается, что длина каждой записи 40 позиций, начальная позиция первой записи нулевая и число записей равно 100.
domains
file=f
predicates
read_file
clauses
read_file:-
write(''Введите ими файла:"),nl,
readln(F),
openmodify(f, F)
write("Введите номер записи: "),nl,
readint(N),
N>0, N<=100, !,
l=(N-1)*40
readdeviсе(f)
filepos(f, l, 0)
readln(C)
write(C), nl, nl,
write(''Нажмите пробел''), nl,
readdeviсе(keyboard),
readchar(_),
closefile(f),
read_file:-write(''*Ошибка ввода*'').
goal
read_file
В случае указания несуществующего имени физического файла или указания несуществующего номера записи в файле печатается сообщение об ошибке ввода.
2.7 Предикаты для работы с окнами
Для организации удобного интерфейса пользователя с Пролог - программой в Турбо-Прологе имеется ряд стандартных предикатов для работы с окнами.
2.7.1 Предикат для создания окон
makewindow(Window_number,
Screen_attribute, t
Frame_attribute
Frame_string
Starting_row
Starting_column
Window_height,
Window_width).
Параметр Window_number, целое число, идентифицирует окно в программе. Это число используется в качестве ссылки предикатом shift_window и др. В длиной программе организуется 5 различных окон, т.е. значение параметра Window_number будет изменяться от 1 до 5.
Целочисленные значения Screen_attribute задают комбинацию цветов текста и фона в окне, Для создаваемых окон выбраны белые символы на черном фоне, т.е. значение параметра Screen_attribute=7.
Для цветного экрана параметр формируется по формуле screen_attribute = S+А, где S - цвет текста, а А - цвет фона (таблица 4)
Таблица 4
Цвет текста (символа) | S | Цвет фона | A |
Черный | Черный | ||
Синий | Синий | ||
Зеленый | Зеленый | ||
Голубой | Голубой | ||
Красный | Красный | ||
Фиолетовый | Фиолетовый | ||
Коричневый | Коричневый | ||
Белый | Белый | ||
Серый | |||
Светло-синий | |||
Светло-зеленый | |||
Светло-голубой | |||
Светло-красный | |||
Светло-фиолетовый | |||
Желтый | |||
Интенсивно-белый |
Для вывода символов с мерцанием параметр формируется по формуле screen_attribute = S+А+128.
Аргумент Frame_attribute есть целое число, значение которого задает цвет рамки (таблица 5). Для белой рамки Frame_attribute = 7.
Аргумент Starting_row - целое число. Определяющее верхнюю строку(лишнюю) создаваемого окна.
Аргумент Starting_column - целое число, указывающее крайний левый столбец Окна.
Аргумент Window_height - целое число, определяющее количество строк, занимаемых создаваемым окном.
Аргумент Window_width - целое число, указывающее число столбцов, занимаемых окном.
2.7.2 Предикат смены текущего окна
shift_window(Window_number).
Параметр Window_number является целым числом, приписываемым окну при его создании. (Это параметр Window_number предиката makewindow).
Значение предиката shift_window(3) вызывает переназначение всех операций ввода и вывода в окно с номером 3.
Таблица 5
Значение аргумента Frame_attribute | Вид рамки | |
Нет рамки | ||
Зеленая рамка | ||
Синяя рамка | ||
Светло-синяя рамка | ||
Красная рамка | ||
5 | Фиолетовая рамка | |
Желтая рамка | ||
Белая рамка | ||
Коричневая рамка | ||
-1 | Мерцающая белая рамка | |
-2 | Мерцающая желтая рамка | |
-3 | Мерцающая фиолетовая рамка | |
-4 | Мерцающая красная рамка | |
-5 | Мерцающая светло-синяя рамка | |
-6 | Мерцающая светло-зеленая рамка | |
-7 | Мерцающая синяя рамка | |
-8 | Мерцающая серая рамка |
2.7.3 Предикат удаления текущего окна с экрана
Removewindows
Все текстовые и графические изображения, находящиеся в окне так же удаляются. Если за данным окном находится другое окно, то это окно и его содержимое становятся видимыми.
2.7.4 Предикат очистки текущего окна
Clearwindow
2.8 Пример организации многооконного меню в программе обработки файла прямого доступа
Модуль menu высвечивает в главном окне программы доступные пользователю функции обработки файла:
- создание файла прямого доступа;
- добавление элемента в файл;
- модификация файла
- просмотр файла;
- окончание работы программы.
Модуль запрашивает у пользователя режим работы N в соответствии с выбранной функцией обработки файла или окончанием работы. С помощью repeat и N=5 осуществляется выбор новых необходимых видов обработки файла. В соответствии с выбранным режимом работы N осуществляется выбор правил:
- process(1) - для создания файла прямого доступа;
- process(2) - для добавления информации в файл;
- process(3) - для модификации информации в файле;
- process(4) - для просмотра информации, находящейся в файле;
- process(5) - для окончания работы программы.
Первые четыре из этих модулей создают свои диалоговые окна.
В программе предусмотрены реакции программы на ошибки при вводе выбираемого режима работы и при не указании имени физического файла.
domains
file=f
predicates
menu
repeat
namefile(string)
input(string)
read
process(integer)
error
clauses
menu:-repeat, makewindow(1, 7, 7, ''ГЛАВНОЕ МЕНЮ'', 0, 0, 25, 70),
write(''****************************************''), nl,
write(''*****ФУНКЦИИ ОБРАБОТКИ ФАЙЛА*****''), nl,
write(''****************************************''), nl,
write("***1. Создание файла ***"), nl,
write("***2. Добавление элемента в файл ***"), nl,
write("***3. Модификация файла ***"), nl,
write("***4. Просмотр файла ***"), nl,
write("***5. Окончание работы ***"), nl,
write(''****************************************"), nl, nl, nl,
write(''ВАШ ВЫБОР (1 ..5): "), readint(N),
process(N), N=5,!.
repeat.
repeat:-repeat.
process(1):-makewindow(2,7,7,"СОЗДАНИЕ ФАЙЛА'',0,10,25,30), nl,nl
write("Введите имя файла ''),readln(F},
namefile(F),
openwrite(f, F),
closefile(f)
openappend(f, F),
write("Будете вводить (y/n): "),
readln(C),
input(C),
closefile(f),
removewindows.
process(2):-makewindow(3,7,7,"ДОБАВЛЕНИЕ ЭЛЕМЕНТА",0,10,25,30), nl, nl,
write("Введите имя файла "),
readln(F),
namefile(F),
openappend(f,F},
input(''y''),
closefile(f),
removewindows.
process(3):-makewindow(4,7,7," ДОБАВЛЕНИЕ ЭЛЕМЕНТА",10,10,10,30), nl, nl,
write("Введите имя файла ''),
readln(F),
namefile(F),
openmodify(f, F),
write("Номер записи: "),
readint(N), l:=(N-1)*7,
readdeviсе(f),
filepos(f, l, 0),
readln(С),
write(C), nl, nl,
readdeviсе(keyboard),
write("Вверните новое значение:"), nl,
readint(K),
filepos(f,1,0),
writedevice(f)
write("%5.0", K),
writedevice(screen),
closefile(t),
removewindows.
process(4):-makewindow(5 7 7 ''ПРОСМОТР ФАЙЛА",0,10,25,30), nl, nl,
write("Введите имя файла "),
readln(F),
namefile(F),
openread(f, F),
readdeviсе(f),
writedevice(screen),
print,
closefile(f),
removewindows.
process(5):-nl, write("КОНЕЦ" ), nl,
write("Нажать пробел"),
readchar(_).
error:-nl,
write("ОШИБКА ВВОДА"), n1,
write("Нажмите пробел" ),
readchar(_).
print: -not(eof(f), !,
readln(N),
write(N), n1,
print.
print:-readdeviсе(keyboard).
namefile(""):-!,
write("***ОШИБКА ВВОДА***"), nl,
write(''Нажмите пробел"),
readchar(),
fail
namefile(f).
input(''y''):-!,
write( ''Ведите элемент: "),
read,
write(''Будете еще вводить? (y/n):''),
readln(C),
input(C)
input(_)
read:-readint(K), !,
writedevice(f),
writef("%5.0", K),
writedevice(screen)
read.