Сибирский университет потребительской кооперации
Опубликован: 04.05.2005 | Доступ: свободный | Студентов: 4322 / 1347 | Оценка: 4.45 / 4.22 | Длительность: 12:28:00
ISBN: 978-5-9556-0034-5
Лекция 12:

Файлы

< Лекция 11 || Лекция 12: 1234 || Лекция 13 >

Содержимое файла можно рассматривать как поток компонентов. Каждый компонент файла находится на какой-то позиции. Для того чтобы узнать текущую позицию чтения или записи в файле, либо для того, чтобы изменить эту позицию, служит предикат filepos.

У него три аргумента. Первый аргумент — это символическое имя файла, второй — позиция внутри первого аргумента, которую нужно узнать или установить, третий — номер режима, который задает, откуда отсчитывается позиция.

Номер режима может принимать одно из трех значений: ноль, единица или двойка.

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

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

Опишем ниже два предиката, служащие для перенаправления потоков ввода-вывода.

Для переопределения текущего устройства ввода или для того, чтобы узнать, какое устройства ввода является текущим, служит предикат readdevice. Этот предикат имеет один параметр, в качестве которого указывается символическое имя файла. Если предикат readdevice используется с несвязанным параметром, то он возвращает в него имя устройства, которое в настоящий момент является активным устройством чтения информации. Если его параметр означен именем открытого для чтения устройства, то этот предикат переопределит активное устройство ввода информации.

Предикат writedevice подобен предикату readdevice, однако используется для переопределения текущего устройства вывода или для получения имени текущего устройства вывода. Он также имеет один параметр, который может быть использован либо как входной, либо как выходной. В первом случае будет переопределено текущее устройство записи информации (должно быть открыто на запись или дозапись), во втором — параметр будет связан с именем активного устройства вывода.

Для записи данных в текущее устройство записи служит уже знакомый нам предикат write, который до этого мы использовали для вывода информации на монитор. Для чтения информации из активного устройства вывода — также уже знакомые нам предикаты readln (читает строку), readint (читает целое), readreal (читает вещественное число), readchar (читает символ), readterm (читает терм).

Имеется также предикат file_str, который целиком читает символы файла в строку или, наоборот, записывает содержимое строки в файл, в зависимости от того, свободен ли второй параметр этого предиката. Первым входным параметром этого предиката является символическое имя файла, а вторым — строка, в которую считывается содержимое файла или из которой записывается информация в него.

Предикат flush используется для принудительной записи в файл содержимого внутреннего буфера, выделенного для файла, указанного в его единственном параметре. Обычно он используется при работе с принтером.

И, наконец, последний встроенный предикат, о котором будет упомянуто в этой лекции, это предикат filemode. Он позволяет узнать или задать режим доступа к файлу. У этого предиката два параметра. Первый параметрсимволическое имя файла, второй параметр задает или принимает режим работы с файлом, имя которого указано в первом параметре. Если второй параметр свободен, то он будет означен текущим режимом работы с файлом, а если связан, то указанный режим будет установлен. Второй параметр может принимать одно из двух значений. Значение ноль соответствует двоичному (бинарному) режиму работы с файлом, а значение единица — текстовому режиму. В текстовом режиме к строкам добавляются символы возврата каретки и перевода строки. Чаще используется текстовый режим, поскольку при работе в двоичном режиме данные можно записывать только посимвольно.

Рассмотрим на примерах, как можно использовать описанные предикаты.

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

При реализации этого предиката воспользуемся встроенными предикатами: existfile для проверки наличия файла на диске; openread для открытия существующего файла на чтение; readdevice для перенаправления ввода; eof для проверки, не исчерпали ли мы содержимое файла ; readchar для чтения символов из файла, write для вывода прочитанного символа на экран.

Сначала напишем вспомогательный предикат, который будет читать символы из файла и выводить их на экран до тех пор, пока не будет достигнут конец файла.

Основной предикат будет проверять существование файла, указанного в качестве его параметра. Если файла с таким именем не существует, будет выдано соответствующее сообщение. Если файл с указанным именем существует, откроем его на чтение предикатом openread и определим его в качестве текущего устройства ввода информации, используя предикат readdevice. Далее воспользуемся нашим вспомогательным предикатом для вывода содержимого файла на экран. Закроем файл предикатом closefile. Сделаем текущим устройством чтения клавиатуру, воспользовавшись предикатом readdevice. В принципе, можно на этом остановиться, а можно организовать паузу до нажатия любой клавиши предикатом readchar(_). До этого неплохо бы вывести сообщение о том, что работа будет продолжена после нажатия любой клавиши.

Так как это — наш первый опыт работы с файлами в Прологе, приведем всю программу целиком, со всеми разделами. В разделе описания внутренней цели организуем ввод имени файла и вызов основного предиката.

DOMAINS /* раздел описания доменов */
file = f /* f — внутреннее имя файла */
PREDICATES /* раздел описания предикатов */
write_file(file)
writeFile(string)
CLAUSES /* раздел описания предложений */
write_file(f):–
          not(eof(f)),!, /* если файл f еще 
                            не закончился */
          readchar(C), /* читаем из него символ */
          write(C," "), /* выводим символ на экран*/
          write_file(f). /* продолжаем процесс */
write_file(_). /* это предложение нужно, чтобы предикат 
                  не потерпел неудачу в случае, когда 
                  будет достигнут конец файла */
writeFile(F_N):–
          existfile(F_N),!, /* убеждаемся в существовании 
                               файла с именем F_N */
          openread(f,F_N), /*  связываем внешний файл F_N 
                               с внутренним файлом f 
                               и открываем его на чтение */
          readdevice(f), /* устанавливаем в качестве 
                            устройства чтения файл f */
          write_file(f), /* вызываем предикат, выводящий 
                            на экран все символы 
                            файла f */
          closefile(f), /* закрываем файл */
          readdevice(keyboard), /* перенаправляем ввод 
                                   на клавиатуру */
          nl,nl, /* пропускаем строку */
          write("Нажмите любую клавишу"), 
                        /* выводим сообщение на экран */
          readchar(_)./* ждем нажатия любой клавиши */
writeFile(F_N):–
          write("Файл с именем ",F_N," не наден!"). 
                        /* выдаем сообщение, если предикат 
                        existfile потерпел неудачу */
GOAL /* раздел описания внутренней цели*/
write("Введите имя файла: "),
readln(F_N), /* читаем название файла в переменную F_N */
writeFile(F_N).
< Лекция 11 || Лекция 12: 1234 || Лекция 13 >
Виктор Бондарь
Виктор Бондарь

После приведения формулы вида ПНФ к виду ССФ вы получаете формулу, в безквантовой матрице которой дизъюнкт содержит оба контранрных атома:. Как тогда проводить его унификацию, если в случае замены x на f(x) весь дизъюнкт обратится в единицу?

Ольга Потапенко
Ольга Потапенко

никак не могу увидеть тексты самих лекций.