Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Solomon.doc
Скачиваний:
17
Добавлен:
08.05.2019
Размер:
3.38 Mб
Скачать

Глава 7. Использование файлов на внешних носителях

7.1. Введение

В главах с 3 по 6 вы учились работать с доменами раз-

личных типов и доменными структурами, списками и строками.

Эти структурированные объекты во время работы обычно содер-

жатся в оперативной памяти компьютера. Теперь вы подготовле-

ны, чтобы начать работать с данными, хранимыми в файлах на

внешних носителях информации.

Работа с данными, содержащимися в файлах называется

файловой обработкой. К числу наиболее типичных операций над

файлами относятся создание файла, запись в файл и чтение из

файла, модификация уже существующего файла и добавление к

нему новых данных.

Турбо-Пролог обеспечивает великолепные возможности для

удобной и эффективной обработки файлов. Сюда можно включить

встроенные предикаты для открытия и закрытия файлов, чтения

из файла и записи в файл, изменения данных в файле, а также

дозапись в уже существующий файл. Данные из файла могут об-

рабатываться либо как непрерывный поток символов, либо как

структурированные объекты типа записей базы данных.

В настоящей главе вы обучитесь технике создания файлов,

обращения к ним и обработке содержащихся в них данных. Вы

также познакомитесь с двумя полезными средствами проектиро-

вания программ: структурной схемой и диаграммой потоков дан-

ных. В дополнение в гл. 9 будет представлен комплекс мето-

дов работы с файлами при использовании конструкций динами-

ческой базы данных.

7.2. Конфигурация компьютера

Обычно файлы располагаются на дисках.Чтобы можно лучше

представить, как система работает с создаваемыми вами файла-

ми здесь будет приведено краткое описание конфигурации пер-

сонального копьютера фирмы IBM .

Составными частями компьютера являются устройства вво-

да-вывода, используемые программой на Турбо-Прологе во время

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

режиме, с клавиатуры в компьютер вводится целевое утвержде-

ние. Программа выводит на экран монитора результаты. Другими

словами, при помощи устройства ввода - клавиатуры и устройс-

тва вывода - монитора осуществляется взаимодействие с прог-

раммой.

Сама система Турбо-Пролог, а вместе с ней и прикладная

программа помещается в оперативную памяти прозвольного дос-

тупа (RAM). Оперативная память является тем местом, откуда

выводится выходная информация, и куда поступает входная.

7.2.1. Физические и логические устройства

На рис. 7.1 показана базисная конфигурация системы, не-

обходимая для работы Турбо-Пролога. По умолчанию устройством

для ввода информации (устройством чтения) в Турбо-Прологе

считается клавиатура, а устройством вывода (устройством за-

писи) - монитор. При наличии этой стандартной конфигурации

вводимая в систему информация поступает с клавиатуры, а вы-

водимая посылается на монитор. Вся работа по передаче данных

от этих устройств в оперативную память, процессор и другие

компоненты компьютера осуществляется средствами операционной

системы.

Клавиатура, монитор и дисковод являются физическими ус-

тройствами. Для понимания конфигурации устройств, как в Тур-

бо-Прологе, так и в других языках программирования, очень

важна концепция логического устройства. И если физические

устройства -это составне части компьютера как такового, то

логическими устройствами являются те объекты, которыми опе-

рирует програмное обеспечение компютера.

Большинство персональных компьютеров оснащено устройст-

вами для работы с дисками, к примеру, одним дисководом для

гибких дисков. Операционная система позволяет трактовать это

одно физическое устройство как два логических: дисковод А: и

дисковод В:. Если вставить в дисковод гибкий диск и ввести

команду DIR A:, то на экран будет выдан каталог директории с

этого диска. Однако, если ввести команду DIR B:, то операци-

онная система выдаст сообщение

Insert diskette for drive B: and strike

any key when ready

(Вставьте гибкий диск в дисковод В: и нажмите произ-

вольную клавишу, когда все будет готово)

Когда вводится команда DIR A:, то единственный физичес-

кий дисковод адресуется как логический дисковод А:; когда же

вводится команда DIR B:, то тот же самый физический дисковод

рассматривается уже как другой логический, т. е. В:. Для уп-

рощения понимания сути дела можно считать, что один и тот же

физический дисковод отождествляется сначала с одним логичес-

ким дисководом, а затем с другим. Похожие вещи имеют место и

в том случае, если одна и та же выводная информация посыла-

ется сначала на экран дисплея, потом на принтер и, наконец,

в файл на диск: одно и то же логическое устройство, так на-

зываемое устройство записи, сначала отождествляется с экра-

ном монитора, потом с принтером и дисководом. Такой процесс

известен под названием переадресации.

Большинство современных языков программирования высоко-

го уровня обеспечивает интерфейс с операционной системой,

который позволяет работать с различными физическими устройс-

твами. Турбо-Пролог обеспечивает эту возможность путем под-

держания предикатов, осуществляющих назначения логических

устройств.

Встроенный предикат Турбо-Пролога readdevice позволя-

ет переадресовать логическое устройство ввода. Аналогично

встроенный предикат writedevice осуществляет переадресацию

устройства вывода информации.

Так предикат

readdevice(myfile)

настраивает устройство ввода на файл myself, а предикат

writedevice(yourfile)

настраивает устройство вывода на файл yourfile.

7.2.2. Стандартная конфигурация устройств

Стандартная конфигурация устройств является по своей

сути встроенным средством языка, позволяющим использовать

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

программы бывает необходимо использовать внешние устройства,

отличные от клавиатуры и монитора. Примером могут служить

принтер (для получения "твердой копии"), телекоммуникацион-

ные порты, а также дисководы. Турбо-Пролог обеспечивает воз-

можность работы со стандартной конфигурацией устройств, ко-

торая включает клавиатуру, дисплей, принтер и коммуникацион-

ный порт.

На рис. 7.2 показана эта стандартная конфигурация уст-

ройств Турбо-Пролога. Принтер здесь подключен к параллельно-

му порту компьютера. Предикатом, адресующим выводную инфор-

мацию на принтер, является writedevice(printer). Коммуника-

ционный порт является первым из последовательных портов, это

порт COM1 (некоторые персональные компьютеры имеют больше

чем один последовательный порт). Предикатом для сброса дан-

ных в порт служит writedevice(com1), для приема данных пред-

назначен предикат readdevice(com1). Число предикатов для об-

служивания порта два. Это обусловлено тем, что данное уст-

ройство можно использовать как для ввода данных (приема из

входной линии связи), так и для их вывода (посылки в выход-

ную линию связи). Клавиатура является устройством, допускаю-

щим лишь ввод , а принтер и монитор - лишь вывод данных.

В Турбо-Прологе некоторые устройства нужно "открыть"

для начала ввода или вывода информации, и "закрыть" после

того, как они стали ненужными. "Открытие" сигнализирует опе-

рационной системе о том, что данное устройство сейчас будет

использоваться; операционная система приводит в готовность

те внутренние ресурсы, которые необходимы для поддержки ра-

боты этого устройства. "Закрытие" устройства информирует

операционную систему о том, что она может завершить поддерж-

ку данного устройства и освободить занятые им ресурсы для

использования их другими компонентами системы.

Ввиду того что клавиатура, монитор, принтер и коммуни-

кационный порт являются стандартными устройствами, для них

подобные операции выполнять не нужно. Турбо-Пролог произво-

дит их автоматически.

Турбо-Пролог использует переадресацию для замены одного

устройства ввода другим. Аналогично обстоит дело и для уст-

ройств вывода. Предположим, что необходимо выдать строку

Into the future сначала на экран, а потом на принтер. Вот

предикаты, которые можно было бы использовать для этой цели:

write("Into the future"),nl,

writedevice(printer),

write("Into the future"),nl,

writedevice(screen).

Первый из предикатов write посылает строку на экран мо-

нитора, поскольку монитор задается в качестве устройства вы-

вода по умолчанию, когда программа стартует. Предикат

writedevice(printer) переадресует вывод на принтер, и второй

предикат write осуществляет печать строки на принтере. Пос-

ледний из написанных предикатов производит обратную переад-

ресацию вывода.

Заметим, что компьютер должен быть оснащен принтером

или коммуникационным адаптером для переадресации ввода или

вывода на COM1 или принтер. Если вы попробуете произвести

переадресацию на отсутствующее устройство, то произойдет

вмешательство DOS, и выполнение Вашей программы будет прек-

ращено.

Программа "Макбет - 1" (листинг 7.1) выводит строки

данных на экран и принтер, демонстрируя таким образом ис-

пользование предикатов переадресации.

_____________________________________________________________

Листинг 7.1

/* Программа: Макбет - 1 Файл: PROG0701.PRO */

/* Назначение: Вывод информации на экран дисплея */

/* и на принтер. */

domains

str = string

predicates

data(str)

write_lines

goal

write_lines.

clauses

data("A drum, a drum!").

data("Macbeth does come").

data("The weird sisters, hand in hand,").

data("Posters of the sea and land,").

data("Thus do go about, about:").

data("Thrice to thine and thrice to mine.").

data("And thrice again, to make up nine.").

write_lines :-

data(Line),

write(" ",Line),nl,

writedevice(printer),

write(" ",Line),nl,

flush(printer),

writedevice(screen),

fail.

write_lines.

/***** конец программы *****/

____________________________________________________________

Правило write_lines использует предикат writedevice для

адресации вывода как на экран, так и на принтер.

write_lines :-

data(Line),

write(" ",Line),nl,

writedevice(printer),

write(" ",Line),nl,

flush(printer),

writedevice(screen),

fail.

write_lines.

Перед тем как испытывается это правило, устройством вы-

вода по умолчанию является монитор. Первая подцель

data(Line), присваивает строковой переменной Line объект од-

ного из утверждений предиката data. Вторая подцель выводит

эту строку на экран монитора. Третья подцель переадресует

вывод на принтер, четвертая осуществляет печать данных, пя-

тая переадресует вывод обратно на экран. Выдача программы,

отрывок из "Макбета" Уильяма Шекспира, приведена на рис.

7.3.

Заметим, что за каждым предикатом write в программе

следует предикат nl. Вы уже знаете, что тогда когда вывод

идет на экран, nl сдвигает курсор к началу следующей строки

видео. Когда данные печатаются на принтере, данный предикат

имеет аналогичную функцию: он сдвигает головку принтера к

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

разборе программы "Вывод файла", вы сможете оценить важность

использования nl при работе с файлами.

* Упражнение

7.1. Напишите фрагмент программы на Турбо-Прологе, который

выдает строку Thank Goodness, It's Friday сначала на прин-

тер, а затем на экран. (Примечание: данный фрагмент можно не

вводить в программу, а задать его в целевом утверждении.)

7.2. Напишите фрагмент программы на Турбо-Прологе, который

выдает строку Look like we're goinng to the Rose Bow! снача-

ла на экран, потом на принтер и, наконец, в коммуникационный

порт. (Сначала при помощи команды операционной системы MODE

нужно настроить коммуникационный порт на работу с устройст-

вом. С командой MODE можно ознакомиться в описании операци-

онной системы DOS.)

7.3. Внесите изменения в программу "Макбет - 1", так чтобы

она выдавала отрывок Вашего любимого стихотворения.

7.2.3. Расширенная конфигурация устройств

Конфигурация устройств в Турбо-Прологе допускает вклю-

чение файлов на диске, которые могут являться для программ

устройствами как ввода, так и вывода. Помимо других преиму-

ществ, использование файлов в качестве логических устройств

ввода-вывода обеспечивает средство хранения баз данных, в

особенности больших, на диске. На рис. 7.4 приведена расши-

ренная конфигурация устройств Турбо-Пролога. Стандартная

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

жат файлы.

К каждому из трех файлов, представленных на рис. 7.4,

можно обратиться как для считывания информации, так и для

записи. Запись включает операции создания нового файла, до-

записи данных к уже существующему файлу, а также модификации

данных на месте.

Чтение из файла предусматривает как считывание всей со-

держащейся в файле информации, так и выборочное считывание.

Для реализации этих операций можно воспользоваться встроен-

ными предикатами Турбо-Пролога.

7.3. Предикаты Турбо-Пролога для работы с файлами

В системе Турбо-Пролог имеются следующие предикаты для

работы с файлами:

deletefile уничтожение файла

save сохранение файла на диске

renamefile переименование файла

existfile тест на наличие файла с данным именем

flush сброс данных из внутреннего буфера

disk выбор дисковода и пути доступа

dir выдача каталога директории

Кратко опишем, как работают предикаты для работы с фай-

лами. В приведенных ниже примерах file_domain является опи-

сываемым пользователем файловым доменом (как это сделать,

будет пояснено в следующем разделе), а DOS_filename - име-

нем, под которым файл фигурирует в директории на диске. В

том случае если пример не очевиден, он снабжается пояснения-

ми.

deletefile(DOS_filename)

save(DOS_filename) Сохраняет на диске утверждения ди-

намической базы данных (смотри гл. 9).

renamefile(Old_DOS_filename,New_DOS_filename)

existfile(DOS_filename) Предикат успешен в случае, если

файл с именем, заданным переменной DOS_filename, присутству-

ет в директории.

flush(file_domain) Этот предикат сбрасывает содержимое

внутреннего буфера, отведенного для данного устройства запи-

си.

disk(Path) Если переменной Path присвоен корректный

путь доступа (смотри приложение С), то заданная с его по-

мощью директория становится текущей. Если же переменная Path

не означена, то данный предикат присваивает Path путь досту-

па к текущей директории.

dir(Path,File_spec,File_name) Переменной Path должен

быть присвоен корректный путь доступа, переменная File_spec

задает расширение представляющей интерес группы файлов. Дан-

ный предикат выдает каталог имен файлов с заданным расшире-

нием; вы можете выбрать среди них нужный и нажать Enter. Имя

файла будет присвоено переменной File_name.

Помимо перечисленных предикатов Турбо-Пролог также под-

держивает предикаты чтения из файла, записи в файл, модифи-

кации файла и тому подобные. Эти предикаты будут рассмотрены

позднее.

7.3.1. Описание файлового домена

Для того чтобы использовать в программе файлы, необхо-

димо снабдить ее описанием файлового домена. Описание одного

файлового домена с именем datafile выглядит как

file = datafile

Это описание не бросается в глаза, так как не похоже на

описания доменов других типов. Куда более привычным кажется

описание типа

name = symbol

где name является именем домена, а symbol - стандартным ти-

пом доменов Турбо-Пролога. При описании файловых доменов,

однако, тип домена file задается по левую сторону от знака

равенства, а имя домена datafile - по правую.

Символическое имя файла типа datafile из настоящего

примера есть идентификатор, который в программе может быть

логически отождествлен с DOS-овским именем файла (именем,

которое можно видеть при выдаче каталога директории). Это

символическое имя называют также логическим именем файла.

В описании file можно указывать несколько символических

имен, но само описание должно быть единственным. Если в

программе вводится несколько символических имен файлов, то

они разделяются между собой точкой с запятой (;) :

file = datafile1; datafile2; datafile3

Это объявление декларирует 3 символических имени для

последующего их отождествления с реальными файлами DOS.

7.3.2. Запись в файл

Перед тем, как начать писать что-либо в файл, нужно

сперва создать его. В Турбо-Прологе файлы создаются при по-

мощи предиката openwrite. Опишем последовательность исполь-

зования предиката openwrite и других действий, необходимых

для записи в файл информации:

1. Открытие файла. Предикат

openwrite(datafile1,"FILE1.DAT").

где datafile1 есть введенный пользователем файловый домен, а

FILE1.DAT - имя файла в DOS, устанавливает связь между объ-

ектами datafile1 и FILE1.DAT. Теперь ссылки на datafile1 бу-

дут означать обращение к FILE1.DAT. Связь остается в силе

вплоть до закрытия файла.

Заметим, что если файл с именем FILE1.DAT к моменту вы-

зова предиката openwrite уже присутствовал в директории, то

его содержимое будет утрачено. Для того, чтобы застраховать-

ся от этой неприятности, можно сначала проверить наличие

файла при помощи предиката

existfile("FILE1.DAT")

и принять соответствующие меры, если existfile будет успе-

шен.

2. Назначение файла в качестве устройства записи. Данную

операцию проделает предикат

writedevice(datafile1).

3. Сама запись в файл. Можно использовать любые подходящие

для этой цели предикаты, например, write или writef. Любой

предикат write будет теперь выводить информацию не на экран,

а в файл.

4. Использование любых других предикатов и правил, отвечаю-

щих назначению программы. Примером может служить переадреса-

ция потока данных с экрана на принтер.

5. Закрытие файла. Этой цели служит предикат

closefile(datafile).

Когда файл закрыт, операции чтения или записи для него недо-

пустимы. Закрытие файла также защищает содержимое файла от

каких бы то ни было манипуляций, так как теперь возможны

лишь операции с файлом в целом.

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

указателя файла в начало. Это может понадобиться при повтор-

ном открытии файла.

Ниже приведен пример фрагмента программы на Турбо-Про-

логе, поясняющий только что сказанное.

openwrite(datafile1,"FILE1.DAT"),

writedevice(datafile1),

< любые правила или предикаты записи в файл >

< любые другие правила или предикаты >

сlosefile(datafile1).

7.3.3. Чтение из файла

В случае, если файл FILE1.DAT уже существует, то с ним

можно поизвести целый ряд операций. Можно считать из файла

все содержащиеся в нем данные, можно считать данные выбороч-

но, можно модифицировать их, а можно произвести дозапись

новых данных в конец файла.

Для чтения данных из файла требуется:

1. Открытие файла

openread(datafile1,"FILE1.DAT")

2. Назначение файла устройством чтения

readdevice(datafile1).

3. Само чтение из файла при помощи соотвествующего предиката

или правила.

4. Использование произвольных предикатов и правил, отвечаю-

щих целям программы.

5. Закрытие файла

closefile(datafile1).

Иллюстрацией может служить

openread(datafile1,"FILE1.DAT"),

readdevice(datafile1),

< любые правила или предикаты чтения из файла >

< любые другие правила или предикаты >

сlosefile(datafile1).

7.3.4. Модификация существующего файла

Последовательность действий, требуемых для модификации

уже существующего файла несколько отличается от той, которая

необходима для записи в файл или чтения из него. Прежде все-

го файл должен быть открыт для модификации (т. е. для чтения

и записи одновременно). Для этой цели служит предикат

openmodify.

Предикат

openmodify(datafile1,"FILE1.DAT")

успешен только в том случае, если файл уже присутствует на

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

предиката openwrite. При этом следует, конечно, помнить, что

openwrite создает новый файл даже тогда, когда файл с таким

именем уже имеется, затирая при этом все, что в нем находи-

лось.

Содержимое файла можно рассматривать как поток симво-

лов. Каждый символ находится в файле на какой-то позиции.

Позиция определяется удаленностью от первого символа файла.

Таким образом первый символ в файле занимает нулевую пози-

цию, второй - первую и т. д. Вообразим себе теперь невидимый

указатель, который можно сместить на любую позицию файла.

Этот указатель определяет позицию,из которой будет прочитан

или в которую будет записан очередной символ.

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

щается в начало файла. Турбо-Пролог позволяет смещать указа-

тель при помощи предиката filepos. filepos будет подробно

рассмотрен в разделе, посвященном файлам прямого доступа. В

настоящий момент Вам требуется знать лишь то, где будет рас-

полагаться указатель после вызова openmodify.

Модификацию файла можно разбить на следующие шаги:

1. Открытие файла

openmodify(datafile1,"FILE1.DAT")

2. Переадресация вывода в файл

writedevice(datafile1)

3.Запись в файл новых данных.

4. Использование произвольных предикатов и правил, отвечаю-

щих целям программы.

5. Закрытие файла

closefile(datafile1)

Примером может служить

openmodify(datafile1,"FILE1.DAT"),

writedevice(datafile1),

< правила для выборочной записи в файл >,

< любые другие правила или предикаты >

сlosefile(datafile1).

7.3.5. Дозапись в конец уже существующего файла

Возможность записать новые данные в конец уже существу-

ющего файла обеспечивается в Турбо-Прологе предикатом

openappend. Когда файл открывается для дозаписи, указатель

файла (см. предыдущий раздел главы) смещается в его конец.

Следующие шаги необходимо предпринять для добавления

новых данных в конец файла:

1. Открытие файла

openappend(datafile1,"FILE1.DAT")

2. Переадресация вывода в файл

writedevice(datafile1).

3. Дозапись в файл новых данных при помощи соответствующих

правил.

4. Использование произвольных предикатов и правил,

отвечающих целям программы. 5. Закрытие файла

closefile(datafile1)

openappend(datafile1,"FILE1.DAT"),

writedevice(datafile1),

< любые правила для дозаписи в файл >,

< любые другие правила или предикаты >

сlosefile(datafile1).

7.4. Средства проектирования программ

В следующем разделе "Использование предикатов для рабо-

ты с файлами" будут приведены программы, демонстрирующие

функциональные возможности описанных предикатов. Эти прог-

раммы, по мнению авторов, более трудны для понимания по

сравнению с теми, которые встречались в предыдущих главах,

что обусловлено их более сложной структурой и использованием

переадресаций ввода-вывода. В настоящем разделе обсуждаются

два инструмента проектирования программ: диаграмма потоков

данных и структурная схема; они могут быть полезны при раз-

работке сложных программ.

Написание программы для компьютера начинается с опреде-

ления задач программы, т. е. того, что она будет делать. Оп-

ределение обычно включает идентификацию входных и выходных

данных и продумывание способа получения желаемого выхода.

Входные данные могут находиться в самой программе, либо пос-

тупать от одного или нескольких внешних источников (устрой-

ств): клавиатуры, дискового файла, коммуникационного порта.

Выходные данные можно высвечивать на экране, печатать на

принтере, записывать в файл или же передавать при помощи

коммуникационного порта.

В Турбо-Прологе задача превращения входных данных в вы-

ходные решается при посредстве целевого утверждения. Цель

программы по обыкновению состоит из ряда подцелей, являющих-

ся предикатами или правилами. Эти предикаты и правила можно

рассматривать как отдельные модули, каждый из которых решает

определенную задачу. Можно вспомнить доменные и предикатные

структурные диаграммы, представленные в гл. 3. Они могут по-

мочь в структуризации доменов и при написании правил, отве-

чающих назначению программы.

По мере того как ваша программа становится все более

сложной, возникает необходимость в новых средствах разработ-

ки, в особенности в средствах планирования структуры прог-

раммы и потоков данных внутри нее.

Правила-модули программы на Турбо-Прологе образуют ие-

рархическую структуру. Структурные схемы (СС), подобные при-

веденной на рис. 7.5, можно использовать для описания функ-

ции программы в целом. СС бывают очень полезны при проекти-

ровании программ.

Главный модуль - цель программы - вызывает три других

модуля. Если перемещаться по схеме слева направо, то первый

из модулей есть предикат openwrite. Задачей этого предиката

является открытие нового файла. Следующим идет правило

write_lines, которое выдает текстовые строки в файл и на эк-

ран.

Для завершения проектирования программы структурную

схему необходимо наполнить содержанием. Начать при этом мож-

но с верхних уровней, которые описывают модули в общих чер-

тах. Описание детализируется на более низких уровнях. В пре-

делах этих структурных модулей уже требуется писать правила

и предикат Турбо-Пролога, отвечающие подцелям модулей.

Такой подход к программированию называется нисходящим

проектированием модулей. Он полностью отвечает требованиям,

предъявляемым к подобным методам, и достаточно эффективен.

Структурная схема является одновременно и инструментом для

организации проектирования программы, и схемой для создания

исходного текста программы. Совместно с методом нисходящего

проектирования они позволяют найти хорошее применение боль-

шинству возможностей Турбо-Пролога.

Во время написания программы необходимо все время пом-

нить, в каких местах данные поступают в программу, а в каких

выводятся из нее. Диаграмма потоков данных (ДПД) (рис. 7.6)

позволяет представить перемещения данных в программе. Эта

диаграмма показывает, что входные данные находятся внутри

самой программы; они содержатся в базе данных. Данные посту-

пают в модуль цели для обработки, а затем выводятся на экран

и в файл для хранения.

Конечно, это очень простой пример. При проектировании

сложных программ, которые состоят из большого числа правил и

содержат много операций ввода-вывода, диаграммы потоков дан-

ных и структурные схемы играют исключительно важную роль,

особенно при разработке структуры программы и ее документи-

ровании. Без них практически невозможно обойтись, если боль-

шая и сложная программа пишется несколькими программистами.

Полезны они также и в том случае, если вы пишете программу в

одиночку. Это позволяет освежить в памяти все детали, когда

возникает необходимость в ее переделке спустя некоторое вре-

мя.

7.5. Использование предикатов для работы с файлами

В предыдущем разделе были рассмотрены два вспомогатель-

ных средства программирования: диаграмма потоков данных и

структурная схема, которые весьма полезны при проектировании

сложных программ, состоящих из целого ряда модулей, завязан-

ных между собой по данным. Примеры программ данного раздела

продолжат знакомство с этими средствами программирования и

продемонстрируют использование предикатов Турбо-Пролога для

работы с файлами.

7.5.1. Создание нового файла

ДПД на рис. 7.6 показывает потоки данных в программе

"Макбет - 2" (листинг 7.2). "Макбет - 2" черпает входные

данные из утверждений базы данных; вывод отправляется на эк-

ран и в файл на диске с именем SHAKE1.DAT.

_____________________________________________________________

Листинг 7.2

/* Программа: Макбет - 2 Файл: PROG0702.PRO */

/* Назначение: Вывод информации на экран дисплея */

/* и в файл на диске. */

domains

str = string

file = datafile

predicates

data(str)

write_lines

goal

openwrite(datafile,"SHAKE1.DAT"),

write_lines,

closefile(datafile).

clauses

data("A drum, a drum!").

data("Macbeth does come").

data("The weird sisters, hand in hand,").

data("Posters of the sea and land,").

data("Thus do go about, about:").

data("Thrice to thine and thrice to mine.").

data("And thrice again, to make up nine.").

write_lines :-

data(Line),

write(" ",Line),nl,

writedevice(datafile),

write(" ",Line),nl,

writedevice(screen),

fail.

write_lines.

/***** конец программы *****/

_____________________________________________________________

Правило для печати выходных данных использует метод от-

ката после неуспеха (ОПН).

write_lines :-

data(Line),

write(" ",Line),nl,

writedevice(datafile),

write(" ",Line),nl,

writedevice(screen),

fail.

write_lines.

Первый из предикатов этого правила (модуля программы)

присваивает переменной Line объект утверждения data. Это

значение затем печатается на заданное по умолчанию устройст-

во вывода, т. е. на экран. Следующие три предиката переадре-

суют вывод в файл, пишут туда данные, потом переадресуют вы-

вод обратно на экран. Предикат fail вызывает откат к следую-

щему утверждению data, так что перебираются все такие утвер-

ждения. Последний write_lines позволяет удовлетворить цель,

когда первый вариант правила дал неуспех ввиду исчерпания

утверждений c data.

Выдача приведенной программы на экран полностью совпа-

дает с выдачей "Макбет - 1". Однако она дополнительно соз-

дает в текущей директории файл с именем SHAKE1.DAT. Для то-

го чтобы ознакомиться с его содержимым, нужно сначала сохра-

нить "Макбет - 2", а затем загрузить SHAKE1.DAT в окно ре-

дактора Турбо-Пролога. Содержимое файла должно почти пол-

ностью совпадать с исходными строками базы данных, за исклю-

чением трех пробелов перед каждой выводимой строкой.

* Упражнение

7.4. Модифицируйте правило write_lines программы "Макбет -2"

так, чтобы сначала данные записывались на диск, а уже потом

выдавались на экран.

7.5.2. Чтение из уже существующего файла

Чтение данных из уже существующего файла является пер-

вичным средством для использования хранящихся на внешнем ус-

тройстве данных. Этот процесс заключается в открытии диско-

вого файла для чтения, выводе их на выходное устройство,

например, экран или принтер, и закрытии файла. (Эти шаги уже

были описаны в разделе "Чтение из файла".) Данный процесс

реализует программа "Распечатка файла" (листинг 7.3).

_____________________________________________________________

Листинг 7.3

/* Программа: Распечатка файла Файл: PROG0703.PRO */

/* Назначение: Чтение данных из файла и вывод их */

/* на экран. */

domains

str = string

file = datafile

predicates

raed_write_lines

goal

openread(datafile,"SHAKE1.DAT"),

read_write_lines,

closefile(datafile).

clauses

read_write_lines :-

readdevice(datafile),

not(eof(datafile)),

readln(line),

writedevice(screen),

write(" ",Line),nl,

read_write_lines.

read_write_lines.

/***** конец программы *****/

На рис. 7.7 и 7.8 приведены диаграмма потоков данных и

структурная схема этой программы. ДПД показывает поток дан-

ных, исходящий из файла SHAKE1.DAT (файл, созданный програм-

мой "Макбет - 2"), и идущий на экран через целевой модуль

программы. СС показывает, что целевой модуль вызывает три

модуля второго уровня. Первый из них производит открытия для

чтения файла SHAKE1.DAT. Второй читает из файла записи и вы-

водит их на экран. Третий, последний, закрывает названный

файл.

Основным звеном программы является правило чтения и вы-

вода данных на экран дисплея.

read_write_lines :-

readdevice(datafile),

not(eof(datafile)),

readln(line),

writedevice(screen),

write(" ",Line),nl,

read_write_lines.

read_write_lines.

Правило использует встроенный предикат Турбо-Пролога

eof, который дает успех в случае, если обнаружен признак

конца файла. Если в процессе чтения из файла данных достига-

ется конец этого файла, то никакие считывания больше не бу-

дут производиться, если, конечно, не сместить указатель фай-

ла на какую-либо позицию, предшествующую метке конца файла.

Неуспешной будет любая подцель, пытающаяся произвести чтение

при указателе, стоящем на этой метке.

Предикат eof(datafile) таким образом сигнализирует о

достижении конца логического файла datafile. Отметим, что в

нашем случае этот предикат употреблен вместе с предикатом

логического отрицания, т. е. в виде not(eof(datafile)). На

естественном языке суть правила можно сформулировать так:

"Продолжать чтение и печать до тех пор, пока не будет дос-

тигнут конец файла".

Используя предикат eof и предусматривая в программе не-

обходимые действия на случай успеха при вызове этого преди-

ката, можно "научить" программу считывать данные из файлов

должным образом. Закрытие, а затем повторное открытие устра-

няют наличие признака конца файла (предикат eof становится

неуспешным), а указатель смещается в начало файла.

Для считывания строк данных из файла SHAKE1.DAT в прог-

рамме использован предикат readln. Как легко вспомнить, в

программах "Макбет" вслед за предикатом write всегда стоял

предикат nl (правило write_lines с листингов 7.1 и 7.2).

Когда nl используется в отношении дискового файла, то в этот

файл записывается индикатор конца строки. Индикатор конца

строки представляет собой пару спецсимволов возврата каретки

и перевода строки (коды ASCII 13 и 10). Иногда эту комбина-

цию обозначают как CR-LF.

Так как nl в правилах следует за предикатом write, то

комбинация CR-LF ограничивает справа каждую из записанных в

файл строк. Когда с этим файлом начинает работать программа

"Распечатка файла", то предикат readln считывает все символы

вплоть до очередной CR-LF. Эффект здесь в точности такой же,

как если бы при вводе строки с клавиатуры нажималась клавиша

посылки.

Последние два предиката переадресуют вывод на экран и

выводят туда данные. Если в программе переадресаций вывода

больше нет, то наличие предиката writedevice(screen) не обя-

зательно. Включение его в программу, конечно, и при этом не

является ошибкой, более того, явное задание устройства выво-

да относится к числу приемов надежного пограммирования. Вы-

дача программы "Распечатка файла" полностью совпадает с вы-

дачей "Макбет - 2".

* Упражнение

7.5. Проделайте с программой "Распечатка файла" следующее:

а. Внесите изменения в правило read_write_lines, так чтобы

входной файл высвечивался на экран и печатался на принтере.

б. Для этой модифицированной программы нарисуйте ДПД и СС.

7.5.3. Запись в файл данных, вводимых с клавиатуры

Одной из наиболее распространенных операций при работе

с файлами является ввод данных с клавиатуры с последующей

засылкой их в файл на диск. Данные, записанные в файл, в

дальнейшем можно редактировать и, вообще, поступать с ними

произвольным образом. Программа "Запись в файл" (листинг

7.4) реализует данную операцию.

_____________________________________________________________

Листинг 7.4

/* Программа: Запись в файл Файл: PROG0704.PRO */

/* Назначение: Считывание данных с клавиатуры и */

/* запись их в файл на диске. */

domains

file = datafile

dstring, cstring = string

predicates

readin(dstring,cstring)

create_a_file

goal

create_a_file

clauses

create_a_file :-

nl,nl,

write("Please enter complete filename."),

nl,nl,

readln(Filename),

openwrite(datafile,Filename),

writedevice(datafile),

readline(Dstring),

concat(Dstring"\13\10",Cstring),

readin(Dstring,Cstring),

closefile(datafile).

readin("done",_) :- !.

readin(_,Cstring) :-

write(Cstring),

readln(Dstring1),

concat(Dstring1,"\13\10",Cstring1),

writedevice(datafile),

readin(Dstring1,Cstring1).

/***** конец программы *****/

____________________________________________________________

На рис. 7.9 показана диаграмма потоков данных; данные

поступают с клавиатуры, идут в модуль цели, и выводятся в

файл на диск. Структурная схема с рис. 7.10 очень проста.

Главный модуль, create_a_file, вызывает модуль readin, осу-

ществляющий чтение и вывод данных.

Имя выходного файла запрашивается с экрана модулем

create_a_file. Когда пользователь вводит имя, Турбо-Пролог

создает на диске новый файл с этим именем. В этот файл запи-

сываются все строки, которые пользователь вводит с клавиату-

ры. Для окончания ввода нужно ввести слово done - сделано

(обратите внимание на обязательность использования при этом

строчных букв), а затем нажать Enter. Создание файла на этом

завершается.

Наиболее важной частью правила create_a_file является

openwrite(datafile,Filename),

writedevice(datafile),

readline(Dstring),

concat(Dstring"\13\10",Cstring),

readin(Dstring,Cstring),

closefile(datafile).

Предикат readln(Dstring) здесь считывает с клавиатуры

первую из вводимых строк. Предикат concat присоединяет к

введенной строке комбинацию \13\10 , т. е. СR-LF. (Это необ-

ходимо для того, чтобы предикат readln мог различать строки

при считывании их из файла в дальнейшем.) Результат конкате-

нации Cstring записывается в выходной файл.

Правило create_a_file в свою очередь вызывает правило

readin, которое продолжает чтение и запись. Первый его вари-

ант

readin("done",_) :- !.

позволяет ему завершиться успешно, если Dstring имеет значе-

ние done. Как известно из главы 3, восклицательный знак пре-

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

оканчивая работу правила.

Второй вариант являет собой рекурсивное правило. Приме-

няемый здесь метод чтения данных до их рекурсивной записи

вообще используется достаточно широко. Этот метод обычно на-

зывается опережающим чтением; смысл этого названия станет

ясен из рассмотрения работы правила.

readin(_,Cstring) :-

write(Cstring),

readln(Dstring1),

concat(Dstring1,"\13\10",Cstring1),

writedevice(datafile),

readin(Dstring1,Cstring1).

Сначала правило выводит полученную при помощи concat

строку в файл. Затем переменная Dstring1 означивается новой

введенной с клавиатуры строкой, эта строка сцепляется с ком-

бинацией CR-LF, и новая полученная таким образом строка

присваивается переменной Cstring1. (Присоединение CR-LF к

строке перед выполнением операции записи в файл дает тот же

эффект, что и предикат nl. В обоих случаях CR-LF помещается

непосредственно за строкой текста.) Вывод переадресуется в

файл на диск, так что данная строка попадет в файл в начале

следующего круга рекурсии readin.

Строго говоря, предикат writedevice(datafile) в правиле

readin не нужен, так как переадресация уже осуществляется

перед первым вызовом этого правила. Однако в том случае,

когда вы захотите вставить в это правило какие-либо еще опе-

рации вывода, то без переадресации уже нельзя будет обой-

тись. Поэтому лучше включить writedevice(datafile) в состав

правила с самого начала.

Программа позволяет пользователю вести диалог с компь-

ютером (рис. 7.11). При этом содержимым файла FROGS.DAT cта-

новятся дополненные CR-LF вводимые пользователем строки.

7.5.4. Чтение файла на диске с последующей выдачей на экран и

принтер

Если вы ввели текст программы "Запись в файл" и порабо-

тали с программой в диалоге, то вы создали на диске новый

файл. Этот файл содержит некоторое число строк, каждая из

которых оканчивается комбинацией CR-LF. Эти строки могут

быть прочитаны и выведены на экран раздельно из-за наличия

CR-LF. Программа "Печать файла" (листинг 7.5) может быть ис-

пользована для чтения и печати на принтер содержимого соз-

данного ранее файла.

_____________________________________________________________

Листинг 7.5

/* Программа: Печать файла Файл: PROG0705.PRO */

/* Назначение: Считывание данных из файла и */

/* вывод их на экран и принтер. */

domains

file = datafile

gstring, cstring = string

predicates

read_and_print

read_and_display_a_file

goal

read_and_display_a_file.

clauses

read_and_display_a_file :-

write("Please enter complete filename."),nl,

readln(Filename),nl,

openread(datafile,Filename),

readdevice(datafile),

read_and_print,

closefile(datafile),

nl,write("Press the space bar."),

readchar(_),exit.

read_and_print :-

not(eof(datafile)),

readln(Cstring),

concat(Cstring,"\13\10",Gstring),

write(Gstring),

writedevice(printer),

write(Gstring),

flush(printer),

writedevice(screen),

read_and_print.

read_and_print :-

eof(datafile), !.

/***** конец программы *****/

____________________________________________________________

На рис. 7.12 и 7.13 приведены диаграмма потоков данных

и структурная схема этой программы. ДПД показывает, что дан-

ные поступают из файла в модуль read_and_display_file, а за-

тем выводятся на экран и на принтер. СС указывает на то, что

главный модуль вызывает модуль read_and_print, назначение

которого есть чтение и печать данных. Этот модуль рекурси-

вен.

Главным модулем программы является

read_and_display_file, он вызывает рекурсивное правило

read_and_print. Наиболее важная часть главного модуля есть

readln(Filename),nl,

openread(datafile,Filename),

readdevice(datafile),

read_and_print,

closefile(datafile).

Приведенные строки вводят имя файла, открывают этот

файл для чтения, а затем вызывают правило read_and_print.

Правило read_and_print содержит предикаты, которые счи-

тывают из файла данные и выводят их на экран и принтер.

read_and_print :-

not(eof(datafile)),

readln(Cstring),

concat(Cstring,"\13\10",Gstring),

write(Gstring),

writedevice(printer),

write(Gstring),

flush(printer),

writedevice(screen),

read_and_print.

Отметим, что в настоящей программе, так же как и в

программе "Запись в файл", справа к строке данных добавляет-

ся комбинация CR-LF. Теперь эти присоединенные символы каж-

дый раз вызывают переход на новую строку. В программе же

"Запись в файл" комбинация добавлялась для того, чтобы пре-

дикат readln мог отличать строки друг от друга. Для этого

предиката CR-LF указывает на окончание строки текста.

Следует также обратить внимание на использование преди-

ката flush(printer). Большинство принтеров не выводят данные

на печать сразу по получению, но лишь тогда, когда целиком

заполняется их внутренний буфер. Предикат flush позволяет

осуществить немедленный вывод накопленной информации.

Пример работы с программой "Печать файла" приведен на

рис. 7.14.

* Упражнение

7.6. Проделайте следующие действия с программами "Запись в

файл" и "Печать файла":

а. Осуществите поочередный запуск обеих программ. Текст для

воода вы можете выбрать по своему собственному усмотрению.

б. Уберите из программы "Запись в файл" операцию конкатена-

ции строки и комбинации спецсимволов CL-LF. Запустите из-

мененный вариант программы на счет и посмотрите, каков будет

результат.

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

каждая выводимая строка предварялась спереди двумя пробела-

ми.

7.5.5. Создание файла, содержащего символьную информацию

Как уже говорилось в предыдущих разделах, программа

"Запись в файл" осуществляет ввод строк с клавиатуры, сцеп-

ляет каждую вводимую строку с комбинацией СR-LF для того,

чтобы строки мог распознать предикат readln из программы

"Печать файла". Таким образом, той минимальной единицей, с

котрой работают программы "Запись в файл" и "Печать файла",

является строка. Другой способ ввода данных с клавиатуры

состоит в представлении вводимой информации в виде потока

символов. Для считывания вводимых с клавиатуры данных здесь

используется предикат readchar. Принципиальным отличием

readchar от readln является то, что readchar не высвечивает

вводимые данные, так что если вы хотите видеть их на экране

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

На рис. 7.15 и 7.16 можно видеть диаграмму потоков дан-

ных и структурную схему программы, использующей этот метод.

Поток данных берет начало от клавиатуры, далее идет к прог-

раммному модулю process_file, а потом раздваивается к экрану

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

process_file вызывает рекурсивный модуль readin, который

осуществляет чтение и запись данных.

Программа "Ввод символов" (листинг 7.6) реализует на

Турбо-Прологе схемы, представленные на рисунках 7.15 и 7.16.

Программа вводит символьные данные с клавиатуры и записывает

их в файл на диск. Попутно вводимая с клавиатуры информация

выводится на экран дисплея.

_____________________________________________________________

Листинг 7.6

/* Программа: Ввод символов Файл: PROG0706.PRO */

/* Назначение: Считывание с клавиатуры символьной */

/* информации и запись ее в файл на диске.*/

domains

file = datafile

predicates

process_file

readin(char)

goal

process_file.

clauses

process_file :-

write("Enter the comlete file name:"),nl,

readln(Filename),

openwrite(datafile,Filename),

writedevice(datafile),

readchar(C),

readin(C),

closefile(datafile).

readin('#') :- !.

readin('\13') :-

write("\13\10"),

writedevice(screen),

write("\13\10"),

readchar(C),

writedevice(datafile),

readin(C).

readin(C) :-

write(C),

writedevice(screen),

write(C),

readchar(C1),

writedevice(datafile),

readin(C1).

/***** конец программы *****/

____________________________________________________________

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

process_file и readin, используют предикат readchar.

readin('#') :- !.

readin('\13') :-

write("\13\10"),

writedevice(screen),

write("\13\10"),

readchar(C),

writedevice(datafile),

readin(C).

readin(C) :-

write(C),

writedevice(screen),

write(C),

readchar(C1),

writedevice(datafile),

readin(C1).

Вторая форма правила readin успешна, когда введен сим-

вол возврат каретки (код ASCII 13); при этом комбинация

CR-LF выводится на экран и в файл, посредством readchar зап-

рашивается следующий символ, далее еще раз рекурсивно вызы-

вается readin. Третья форма правила успешна при вводе любого

другого символа. Это правило, так же как и второй вариант

readin, вводит следующий символ и еще раз рекурсивно вызыва-

ет readin.

При вводе символа "фунт стерлингов" (#) успешен первый

вариант правила, рекурсивных вызовов в нем нет, поэтому под-

цель readin(C) удовлетворена, и, следовательно, испытывается

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

ется, а программа завершает работу.

* Упражнение

7.7. Запустите на счет программу "Ввод символов". Введите

имя файла - MYPOEM.DAT и наберите на экране Ваше любимое

стихотворение (желательно, не очень большое). Ознакомтесь с

содержимым созданного файла при помощи редактора Турбо-Про-

лога.

7.5.6. Считывание символов из файла

Вы познакомились с двумя способами ввода данных с кла-

виатуры. Первый из них использует предикат readln, второй -

предикат readchar. Как вы увидите чуть дальше, readchar мож-

но применять и для считывания данных из файла на диске.

Рис. 7.17 и 7.18 содержат диаграмму потоков данных и струк-

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

водит их на экран и печатает на принтере.

Программа "Чтение символов" (листинг 7.7) реализует эти

схемы на языке Турбо-Пролог.

_____________________________________________________________

Листинг 7.7

/* Программа: Чтение символов Файл: PROG0707.PRO */

/* Назначение: Считывание из файла символьной */

/* информации и вывод ее на экран. */

domains

file = datafile

predicates

process_file

read_and_print_file

goal

process_file.

clauses

process_file :-

write("Enter the comlete file name:"),nl,

readln(Filename),

openread(datafile,Filename),

readdevice(datafile),

read_and_print_file,

closefile(datafile).

read_and_print_file :-

not(eof(datafile)),

readchar(Y),

writedevice(printer),

write(Y),

flush(printer),

writedevice(printer),

read_and_print_file.

read_and_print_file :-

nl,nl,

readdevice(keyboard),

write("Please press the space bar"),

readchar(_).

/***** конец программы *****/

_____________________________________________________________

Модуль, осуществляющий рекурсивный ввод и вывод, есть

правило read_and_print_file:

read_and_print_file :-

not(eof(datafile)),

readchar(Y),

writedevice(printer),

write(Y),

flush(printer),

writedevice(printer),

read_and_print_file.

Предикат readchar здесь используется как для чтения пе-

чатных символов (данных из файла), так и управляющих симво-

лов типа комбинации CR-LF.

* Упражнение

7.8. Запустите на счет программу "Чтение символов". Введите

имя файла FROGS.DAT (то же самое, что вы использовали при

запуске программы "Запись в файл"). На экране должны поя-

виться 3 строки текста, которые вы ввели при запуске "Запись

в файл".

7.6. "Дружественные пользователю" программы для обработки

файлов

Представленные в предыдущих разделах программы рассчи-

чаны на минимум взаимодействия с пользователем во время ра-

боты. Принято, однако, включать в программу модули, которые

при работе с программой оказывают пользователю посильную по-

мощь. Обычно эти модули предоставляют возможность работать с

меню, а также выдают информационные сообщения. Они могут

также включать еще некоторые полезные средства в дополнение

к этим основным, например, давать пользователю время поду-

мать над тем, какие данные ему вводить.

7.6.1. Запись данных в файл

Программа "Ввод данных" (листинг 7.8) является примером

"дружески настроенной по отношению к пользователю" програм-

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

ных.

_____________________________________________________________

Листинг 7.8

/* Программа: Ввод данных Файл: PROG0708.PRO */

/* Назначение: Ввод данных с клавиатуры и */

/* запись их в файл на диске. */

domains

file = datafile

dstring,cstring = string

predicates

write_message_1

check_for_ready

give_instruction

process_input_output

process_file

write_message_2

readin(dstring,cstring)

create_a_file

goal

create_a_file.

clauses

create_a_file :-

write_message_1,

process_file,

write_message_2,

nl,nl,write("Press the space bar."),

readchar(_),exit.

process_file :-

check_for_ready,

give_instruction,

process_input_output.

write_message_1 :-

nl,write("Hello"),

nl,write("This program accepts data from"),

write("keyboard and writes to a file."),nl.

check_for_ready :-

write("PLEASE PRESS SPACE BAR WHEN"),

write(" YOU ARE READY TO BEGIN."),nl,

readdevice(keyboard),

readchar(_).

give_instruction :-

nl,write("You type in data from the keyboard."),

nl,write("You terminate the input process,"),

write(" enter 'done'. Thank you."),nl.

process_input_output :-

write("Please enter comlete filename."),

write(" Then press the return key."),nl,

write("The format of the file name is"),

write(" <file name>.<extension>."),nl,nl,

readln(Filename),

nl,write("Start typing in . . . "),nl,

openwrite(datafile,Filename),

writedevice(datafile),

readln(Dstring),

concat(Dstring,"\13\10",Cstring),

readin(Dstring,Cstring),

closefile(datafile).

write_message_2 :-

writedevice(screen),

nl,write("Your data has been written to the file."),

write(" All done, bye!").

readin("done",_) :- !.

readin(_,Cstring) :-

write(Cstring),

readln(Dstring1),

concat(Dstring1,"\13\10",Cstring1),

writedevice(datafile),

readin(Dstring1,Cstring1).

/***** конец программы *****/

_____________________________________________________________

Рис. 7.19 и 7.20 демонстрируют диаграмму потоков данных

и структурную схему этой программы. "Ввод данных" содержит

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

вателя. Главным в программе является модуль, реализованный

при помощи правила

create_a_file :-

write_message_1,

process_file,

write_message_2,

nl,nl,write("Press the space bar."),

readchar(_),exit.

Первый и последний из модулей второго уровня снабжают

пользователя необходимой ему информацией.

write_message_1 :-

nl,write("Hello"),

nl,write("This program accepts data from"),

write("keyboard and writes to a file."),nl.

write_message_2 :-

writedevice(screen),

nl,write("Your data has been written to the file."),

write(" All done, bye!").

Как нетрудно видеть, первое сообщение поясняет, как

пользоваться программой, и что она делает. Второе информиру-

ет о том, что программа проделала, а также сообщает об окон-

чании ее работы.

Второй модуль второго уровня, process_file, вызывает

три модуля третьего уровня:

process_file :-

check_for_ready,

give_instruction,

process_input_output.

Каждый из них отвечает за выполнение вполне определенного

задания; общим для них является то, что все они дают пользо-

вателю необходимую информацию о своей работе.

Назначение check_for_ready состоит в проверке готовнос-

ти пользователя к диалогу с программой.

check_for_ready :-

write("PLEASE PRESS SPACE BAR WHEN"),

write(" YOU ARE READY TO BEGIN."),nl,

readdevice(keyboard),

readchar(_).

Заметим, что предикат readchar(_) здесь содержит под-

черк, обозначающий анонимную переменную. Модуль ожидания,

подобный данному, может быть полезен в большинстве диалого-

вых программ.

Модуль give_instructions инструктирует о том, как ис-

пользовать программу:

give_instruction :-

nl,write("You type in data from the keyboard."),

nl,write("You terminate the input process,"),

write(" enter 'done'. Thank you."),nl.

Три последних предиката write сообщают о том, что для

окончания ввода требуется ввести done. Такие замечания быва-

ют очень важны для пользователя, так как зачастую именно они

опеределяют, сможет ли человек правильно воспользоваться

программой.

Ядром программы является модуль process_input_output.

Он запрашивает имя файла и начинает чтение и запись данных.

process_input_output :-

write("Please enter comlete filename."),

write(" Then press the return key."),nl,

write("The format of the file name is"),

write(" <file name>.<extension>."),nl,nl,

readln(Filename),

nl,write("Start typing in . . . "),nl,

openwrite(datafile,Filename),

writedevice(datafile),

readln(Dstring),

concat(Dstring,"\13\10",Cstring),

readin(Dstring,Cstring),

closefile(datafile).

Модуль вызывает рекурсивное правило readin для продол-

жения процесса ввода и записи данных. readin здесь ничем не

отличается от аналогичного правила из программы "Запись в

файл". Предикат write("Start typing in . . .") сообщает

пользователю о готовности программы принять на вход первую

из строк, что является достаточно удачным дополнением к

программе.

ДПД с рис. 7.19 показывает поток данных и устройства,

используемые данной программой. На рисунке шесть модулей,

устройство чтения - клавиатура и устройства вывода - экран и

дисковый файл, обозначенный переменной Filename. На диаграм-

ме отражены все направления перемещения данных.

Убедиться в удобстве работы с программой можно, запус-

тив ее на счет. Часть протокола диалога с ней приведена на

рис. 7.21. Нетрудно видеть всю важность написания четких ин-

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

Хотя может показаться, что эстетические качества в этом деле

не играют решающей роли, следует сказать, что это далеко не

так.

* Упражнение

7.9. Модифицируйте программу "Ввод данных", введя дополни-

тельные подсказки по вашему усмотрению. Убедитесь в правиль-

ности работы нового варианта программы.

7.6.2. Чтение из файла

Дружески настроенная к пользователю программа должна

обеспечивать выдачу сообщений о том, как начать работу, как

задать имя файла, и как делать необходимые временные задерж-

ки, чтобы пользователь мог усвоить прочитанную с экрана ин-

формацию. Программа "Чтение файла" (листинг 7.9) удовлетво-

ряет всем этим требованиям.

____________________________________________________________

Листинг 7.9

/* Программа: Чтение файла Файл: PROG0709.PRO */

/* Назначение: Чтение данных из файла и вывод их */

/* на экран и принтер. */

domains

file = datafile

predicates

write_message_1

check_for_ready

process_file

process_input_output

write_message_2

read_and_print

create_output_from_a_file

goal

create_output_from_a_file.

clauses

create_output_from_a_file :-

write_message_1,

process_file,

write_message_2.

process_file :-

check_for_ready,

process_input_output.

write_message_1 :-

nl,nl,write("HELLO"),nl,nl,

write("This program reads and writes "),

nl,

write("data from a data file."),

nl,nl.

check_for_ready :-

write("PLEASE PRESS SPACE BAR WHEN"),

nl,

write(" YOU ARE READY TO BEGIN."),

nl,nl,

readdevice(keyboard),

readchar(_).

process_input_output :-

write("Please enter comlete filename."),

nl,

write(" Then press the return key."),nl,

write("The format of the file name is"),

nl,

write(" <file name>.<extension>."),

nl,nl,

readln(Filename),

nl,

openread(datafile,Filename),

readdevice(datafile),

read_and_print,

closefile(datafile).

write_message_2 :-

writedevice(screen),

nl,nl,

write("Printing of data from the file."),

nl,

write("has been completed."),nl,nl,

write(" Good bye !"),nl.

read_and_print :-

not(eof(datafile)),

readchar(Y),

write(Y),

writedevice(printer),

write(Y),

flush(printer),

writedevice(screen),

read_and_print.

read_and_print :-

nl,nl,

write("Please press the space bar"),

readdevice(keyboard),

readchar(_).

/***** конец программы *****/

____________________________________________________________

Схема этой программы во многом совпадает со схемой

программы программы "Ввод данных". Программа состоит из се-

ми модулей. Вспомогательные модули отвечают за выдачу необ-

ходимых по ходу работы сообщений. Модуль process_input_out-

put запрашивает имя файла, а затем начинает обрабатывать

файл с указанным именем.

process_input_output :-

write("Please enter comlete filename."),

nl,

write(" Then press the return key."),nl,

write("The format of the file name is"),

nl,

write(" <file name>.<extension>."),

nl,nl,

readln(Filename),

nl,

openread(datafile,Filename),

readdevice(datafile),

read_and_print,

closefile(datafile).

В процессе работы он вызывает другой модуль, read_and_print,

предназначенный для чтения и вывода данных.

read_and_print :-

not(eof(datafile)),

readchar(Y),

write(Y),

writedevice(printer),

write(Y),

flush(printer),

writedevice(screen),

read_and_print.

Модуль read_and_print за один раз читает и пишет один

символ, его можно назвать "считывателем символов". Подобный

модуль читает любой текстовый файл, вне зависимости от того,

были ли записаны в него данные как строки или как символы.

Следует, однако, иметь в виду, что операция посимвольного

чтения данных занимает гораздо большее время, нежели чтение

данных по строкам. Поэтому за исключением тех случаев, когда

требуется просмотр и обработка каждого символа входного по-

тока, более эффективны программы, работающие со строками.

* Упражнения

7.10. Запустите на счет программу "Чтение файла". В ответ на

запрос введите имя уже существующего файла.

7.11. Нарисуйте ДПД и СС данной программы. В этом вам помо-

гут рис. 7.19 и 7.20.

7.7. Дозапись данных в файл

Добавление данных в конец уже имеющегося на диске файла

широко применяется в практике программирования. По мере то-

го как появляется новая информация, ее необходимо добавить в

конец файла с уже оприходованной информацией. Подобным обра-

зом устроены экспертные системы и файлы баз данных. Програм-

ма "Игроки" (листинг 7.10) реализует типовой способ дозаписи

данных в файл. Эта программа считывает строки данных, вводи-

мые с клавиатуры, и помещает их в конец выбранного пользова-

телем файла.

____________________________________________________________

Листинг 7.10

/* Программа: Игроки Файл: PROG0710.PRO */

/* Назначение: Чтение данных с клавиатуры и */

/* дозапись в файл на диске. */

domains

file = datafile

dstring,cstring = string

predicates

write_message_1

check_for_ready

give_instruction

process_input_output

process_file

write_message_2

readin(dstring,cstring)

append_a_file

goal

append_a_file.

clauses

append_a_file :-

write_message_1,

process_file,

write_message_2,

nl,write("Press the space bar."),

readchar(_),exit.

process_file :-

check_for_ready,

give_instruction,

process_input_output.

write_message_1 :-

nl,write("Hello"),

nl,write("This program accepts data from"),

write("keyboard and appends it to a file."),nl.

check_for_ready :-

write("PLEASE PRESS SPACE BAR WHEN"),

write(" YOU ARE READY TO BEGIN."),nl,

readdevice(keyboard),

readchar(_).

give_instruction :-

nl,write("You type in data from the keyboard."),

nl,write("You terminate the input process,"),

write(" enter 'done'. Thank you."),nl.

process_input_output :-

write("Please enter comlete filename."),

write(" Then press the return key."),nl,

write("The format of the file name is"),

write(" <file name>.<extension>."),nl,nl,

readln(Filename),

nl,write("Start typing in . . . "),nl,

openappend(datafile,Filename),

writedevice(datafile),

readln(Dstring),

concat(Dstring,"\13\10",Cstring),

readin(Dstring,Cstring),

closefile(datafile).

write_message_2 :-

writedevice(screen),

nl,write("Your data has been appended to the file."),

write(" All done, bye!").

readin("done",_) :- !.

readin(_,Cstring) :-

write(Cstring),

readln(Dstring1),

concat(Dstring1,"\13\10",Cstring1),

writedevice(datafile),

readin(Dstring1,Cstring1).

/***** конец программы *****/

____________________________________________________________

Программа также оснащена модулями, делающими ее "дру-

жественной пользователю". Структура программы схожа со

структурой "Ввода символов" программы, которая читала данные

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

файл.

Основой программы является модуль process_input_output.

process_input_output :-

write("Please enter comlete filename."),

write(" Then press the return key."),nl,

write("The format of the file name is"),

write(" <file name>.<extension>."),nl,nl,

readln(Filename),

nl,write("Start typing in . . . "),nl,

openappend(datafile,Filename),

writedevice(datafile),

readln(Dstring),

concat(Dstring,"\13\10",Cstring),

readin(Dstring,Cstring),

closefile(datafile).

Предикат openappend используется здесь для открытия уже

существующего файла с целью дозаписи в него новых данных.

Модуль readin перенесен без изменений из программы "Чтение

файла".

Вспомогательные модули данной программы выводят на эк-

ран сообщения, содержащие подсказку для пользователя. Для

пояснения работы программы предположим, что мы хотим доба-

вить данные в файл с именем BROWNS.DAT, который содержит

строчки

browns("Chip Banks",26,"6-4",233,"WR").

browns("Gari Danielson",34,"6-2",195,"QB").

browns("Bob Golic",29,"6-2",260,"NT").

Для того чтобы пополнить статистику об игроках, необхо-

димо запустить программу "Игроки" на счет. Протокол диалога

с программой приведен на рис. 7.22.

Теперь файл BROWNS.DAT несколько увеличил свой объем.

Для просмотра его содержимого можно воспользоваться редакто-

ром Турбо-Пролога. Вы увидите пять строк, расположенных в

порядке очередности ввода.

* Упражнение

7.12. Нарисуйте ДПД и СС для программы "Игроки". Запустите

программу на счет и добавьте новые данные к одному из фай-

лов, созданных демонстрационными программами этой главы. Оз-

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

вашей программы.

7.8. Использование файлов прямого доступа

Как нетрудно вспомнить, в разделе "Модификация уже су-

ществующего файла" говорилось, что каждый символ в файле за-

нимает определенную позицию, которая характеризуется рассто-

янием, или смещением, от первого символа файла. Указатель

файла может быть помещен в любую позицию, тем самым он опре-

деляет место, из которого будет считан или в которое будет

записан следующий символ. Файлы с такой организацией доступа

к хранящейся в ней информации называются файлами прямого

доступа, а операции выборки из такого файла - вводом-выводом

из файла прямого доступа.

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

можным чтение и запись логических структур, таких как, нап-

ример, записи, с любой позиции файла. В файлах, используемых

для этих целей, все записи имеют одинаковую длину. Когда

указатель файла перемещается по позициям, номера которых

кратны длине записи, он всегда указывает на начало очередной

записи. Турбо-Пролог содержит два встроенных предиката, ко-

торые удобны для работы с файлами прямого доступа:

openmodify и filepos. В настоящем разделе мы поясним, как

нужно пользоваться ими.

Предположим, что вы хотите модифицировать файл с именем

PLAYERS.DAT. Тогда предикат openmodify необходимо записать в

в виде

openmodify(players,"PLAYERS.DAT").

Символическое имя players обозначает логический файл

программы. Предикат openmodify связывает логическое имя фай-

ла с именем файла в DOS, так что впоследствии все ссылки на

players будут интерпретироваться как ссылки на PLAYERS.DAT.

(Само собой разумеется, что файл с таким именем уже должен

быть создан.)

Предикат filepos записывается в форме

filepos(Logical_filename,File_position,Mode).

Параметру File_position здесь должно быть присвоено

действительное число, обозначающее позицию в файле, из кото-

рой будет считан или в которую будет записан символ. (Дроб-

ная часть числа отбрасывается.)

Параметру Mode может быть присвоено одно из трех значе-

ний: 0, 1 или 2. Эти значения определяют то, как будет ин-

терпретировано значение File_position. В табл. 7.1 пояснено

употребление каждого допустимого значения параметра Mode.

Таблица 7.1. Режимы работы предиката filepos

____________________________________________________________

Режим (Mode)│ Действия системы

____________│_______________________________________________

0 │ Смещение берется относительно начала файла.

1 │ Смещение берется относительно текущей позиции.

2 │ Смещение берется относительно конца файла.

____________│_______________________________________________

Рассмотрим, для примера, такое употребление предиката

filepos:

filepos(players,100,0).

В этом выражении players есть имя логического файла.

Параметр File_position имеет значение 100, что указывает на

то, что будет прочитан символ, стоящий в 100-й позиции. Зна-

чение 0 параметра Mode свидетельствует о том, что сотня бу-

дет отсчитываться от начала файла.

Если в этой записи 0 заменить на 1,

filepos(players,100,1).

то отсчет будет вестись уже относительно текущей позиции

указателя. Если данный предикат будет успешен, то указатель

сдвинется на 100 позиций вперед.

В этом разделе мы разберем две программы. Первая из них

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

данные. Вторая программа читает эти данные, используя в ка-

честве второго параметра предиката переменную.

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

Разработка программы для создания файлов прямого досту-

па начинается с вопроса организации данных. Предположим,

например, что файл должен содержать информацию об игроках

футбольных команд. Назовем этот файл PLAYERS.DAT. В файле

будут записаны имена футболистов, названия их команд и номе-

ра, под которыми они выступают.

John Elway, 7, Denver Broncos---------

Jim McMahon, 9, Chicago Bears---------

Bernie Kosar, 19, Cleveland Browns----

Phil Sims, 11, New York Giants--------

Вся информация состоит из 4 строк, каждая из которых

содержит 38 символов. Допустим, что вы хотите извлекать дан-

ные из файла выборочно. Чтобы добиться этого, необходимо до-

бавить в конец каждой строки комбинацию символов LF-CR. В

результате этой операции длина строки файла достигает 40.

Так как длины всех четырех строк равны, мы имеем дело со

строками фиксированной длины. В каждой строке присутствует

некоторое количество дефисов, которые служат для дополнения

каждой строки до 38 символов.

В настоящем разделе будут описаны основные операции по

модификации данных имеющегося файла. Приведенные ниже прави-

ла используют некоторые из них:

create_a_random_access_file :-

openwrite(datafile,Filename),

closefile(datafile),

openmodify(datafile,Filename),

readln(Dstring),

write_read_more(0,Dstring),

closefile(datafile).

Первые два предиката openwrite и closefile создают

файл, который первоначально пуст. Предикат openmodify откры-

вает этот файл с целью модификации его (записи данных). Пре-

дикат readln читает строку данных с клавиатуры, а предикат

write_read_more записывает считанные строки в файл и читает

новые.

Программа "Создание файла прямого доступа" (листинг

7.11) использует правило, сходное с только что приведенном.

Главным модулем программы является create_a_random_access_

file. Он вызывает модуль write_and_read_more, который реали-

зован в виде рекурсивного правила, пишущего и читающего дан-

ные на каждом круге рекурсии. Рекурсии оканчиваются, когда

пользователь введет слово done.

____________________________________________________________

Листинг 7.11

/* Программа: Создание файла прямого доступа */

/* Файл: PROG0711.PRO */

/* Назначение: Чтение данных с клавиатуры и */

/* запись их на диск в файл прямого */

/* доступа. */

domains

file = datafile

predicates

create_a_random_access_file

write_read_more(real,string)

pad_string(string,string,integer)

goal

create_a_random_access_file.

clauses

create_a_random_access_file :-

write("Please enter filename:"),nl,

readln(Filename),

openwrite(datafile,Filename),

closefile(datafile),

openmodify(datafile,Filename),

write("Type in data string."),nl,

readln(Dstring),

write_read_more(0,Dstring),

closefile(datafile).

write_read_more(_,"done") :-

nl, write(" Press the space bar."),

readchar(_),exit.

write_read_more(Index,Dstring) :-

writedevice(datafile),

filepos(datafile,Index,0),

pad_string(Dstring,Padstring,38),

concat(Padstring,"\10\13",Cstring),

write(Cstring),

writedevice(screen),

write("Type in data string"),nl,

readln(Dstring1),

Index1 = Index + 40,

write_read_more(Index1,Dstring1).

pad_string(Instring,Instring,Length) :-

str_len(Instring,Testlength),

Testlength >= Length,!.

pad_string(Instring,Padstring,Length) :-

concat(Instring,"-",Newstring),

pad_string(Newstring,Padstring,Length).

/***** конец программы *****/

____________________________________________________________

Рекурсивное правило дополняет строку до 38 символов,

сцепляет ее с комбинацией спецсимволов СR-LF и записывает

эту удлиннившуюся строку в файл:

write_read_more(_,"done") :-

nl, write(" Press the space bar."),

readchar(_),exit.

write_read_more(Index,Dstring) :-

writedevice(datafile),

filepos(datafile,Index,0),

pad_string(Dstring,Padstring,38),

concat(Padstring,"\10\13",Cstring),

write(Cstring),

writedevice(screen),

write("Type in data string"),nl,

readln(Dstring1),

Index1 = Index + 40,

write_read_more(Index1,Dstring1).

Отметим, что значение переменной Index (используемой

предикатом filepos) увеличивается на 40 перед очередным кру-

гом рекурсии. При помощи устроенной таким образом индесксной

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

записи помещается в нужное место.

Правило write_read_more использует правило pad_string

для дополнения строки дефисами. Это правило выглядит так:

pad_string(Instring,Instring,Length) :-

str_len(Instring,Testlength),

Testlength >= Length,!.

pad_string(Instring,Padstring,Length) :-

concat(Instring,"-",Newstring),

pad_string(Newstring,Padstring,Length).

Окончание рекурсий связано с выравниванием значений

длины текущей строки и переменной Length.

Ввод строки с дополнением ее до заданного количества

символов весьма полезен при работе со строками фиксированной

длины. В правиле pad_string строка заполняется дефисами, хо-

тя программисты обычно предпочитают использовать для этой

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

длина введенной строки превышает заданное ограничение на

длину строк.

Рис. 7.23 демонстрирует пример диалога с программой

"Создание файла прямого доступа". Как видно из рисунка, файл

прямого доступа имеет здесь имя PLAYERS.DAT. Все строки дан-

ных имеют длину 38.

* Упражнения

7.13. Спроектируйте файл прямого доступа, содержащий инфор-

мацию об автомобильных запчастях: номер, название, количест-

во, цена за штуку.

7.14. Напишите на Турбо-Прологе программу, заводящую на дис-

ке файл, описанный в предыдущем утверждении.

7.8.2. Чтение из файла прямого доступа

Операция чтения из файла прямого доступа требует знания

структуры этого файла. Нужно знать, к примеру, длину каждой

записи файла, число записей, начальную позицию первой запи-

си. Напомним, что любая строка файла PLAYERS.DAT, созданного

программой предыдущего раздела, содержала 40 символов. На-

помним также, что первая строка файла начиналась с нулевой

позиции, поэтому первые символы записанных в файле строк

имели позиции 0, 40, 80 и 120 соответственно.

Правило для чтения этого файла есть

read_a_random_access_file :-

openread(datafile,Filename),

write("Type in record number: "),nl,

readreal(Record),

filepos(datafile,Index,0),

readln(Cstring),

write(Cstring), nl,nl,

closefile(datafile).

Предикат openread в этом правиле используется, чтобы

открыть файл для чтения, имеющий логическое имя datafile.

Предикат readreal вводит с клавиатуры номер выбранной поль-

зователем записи файла. Предикат readdevice переадресует

ввод на файл datafile. Предикат filepos настраивает указа-

тель на определенную пользователем позицию файла; значение 0

параметра Mode задает отсчет от начала файла. readln осущес-

твляет чтение строки, начинающейся с позиции, на которую

ссылается указатель; эта строка означивает переменную

Cstring. Отметим отсутствие в теле правила предиката

openmodify, это связано с тем, что другие устройства ввода

не используются.

В программе "Чтение файла прямого доступа" (листинг

7.12) это правило используется для организации чтения запи-

сей из файла прямого доступа.

____________________________________________________________

Листинг 7.12

/* Программа: Чтение файла прямого доступа */

/* Файл: PROG0712.PRO */

/* Назначение: Чтение данных из файла прямого */

/* доступа и выдача их на экран. */

domains

file = datafile

predicates

read_a_random_access_file

goal

read_a_random_access_file.

clauses

read_a_random_access_file :-

write("Please enter filename:"),nl,

readln(Filename),

openread(datafile,Filename),

write("Type in record number: "),nl,

readreal(Record),

Index = (Record - 1) * 40,

readdevice(datafile),

filepos(datafile,Index,0),

readln(Cstring),

write(Cstring), nl,nl,

write("Press the space bar."),nl,

readdevice(keyboard),

readchar(_),

closefile(datafile),

exit.

/***** конец программы *****/

____________________________________________________________

Программа содержит одно единственное правило, которое

используется в целевом утверждении:

read_a_random_access_file :-

write("Please enter filename:"),nl,

readln(Filename),

openread(datafile,Filename),

write("Type in record number: "),nl,

readreal(Record),

Index = (Record - 1) * 40,

readdevice(datafile),

filepos(datafile,Index,0),

readln(Cstring),

write(Cstring), nl,nl,

write("Press the space bar."),nl,

readdevice(keyboard),

readchar(_),

closefile(datafile),

exit.

Проследим, как вычисляется значение переменной Index. В

теле правила введенный номер записи уменьшается на единицу,

а затем умножается на длину строки, т. е. 40; это значение

присваивается переменной Index. Если полученное число задает

позицию в пределах файла, то правило успешно, и строка дан-

ных высвечивается на экране. Далее программа выдает пригла-

шение продолжить работу и закрывает входной файл.

Рис. 7.24 содержит протокол диалога с программой. Здесь

для считывания была выбрана первая строка,и на экран выве-

лись сведения об игроке по имени John Elway.

* Упражнения

7.15. Измените программу "Чтение файла прямого доступа" так,

чтобы она распечатывала содержимое всего файла.

7.16. Модифицируйте программу "Чтение файла прямого доступа"

так, чтобы она печатала данные из считанной строки в таком

формате:

Имя: <имя игрока>

Номер: <номер>

Команда: <название команды>

(Замечание: Выделить нужные данные из считанной строки можно

при помощи предиката substring (смотри гл. 6).)

7.9. Заключение

В этой главе вы узнали о том, как создавать файлы и ис-

пользовать их в программах на Турбо-Прологе. вы познакоми-

лись со встроенными предикатами Турбо-Пролога, предназначен-

ными для обработки файлов: openwrite, openread, openmodify,

closefile, readdevice, writedevice, eof и filepos - ознаком-

ление велось на примерах программ, использующих эти предика-

ты. Были также описаны и другие предикаты, работающие с

внешними устройствами - save, rename, delete, disk, dir,

existfile и flush.

Вы узнали, что обрабатываемые данные можно представить

либо как поток символов, либо как строки. Было отмечено, что

при работе с дисковыми файлами широко применяются спецсимво-

лы: перевод строки и возврат каретки; с их помощью строки

отделяются друг от друга. Было уделено большое внимание по-

нятию потока данных и связанным с ним предикатам переадреса-

ции ввода - readdevice и вывода - writedevice. Рассматрива-

лись также предикаты печати символа на экран - writechar,

ввода символа без одновременного высвечивания его на экране

- readchar, ввода строки с автоматической выдачей ее на эк-

ран - readln.

Вы познакомились с современными методами проектирования

программ. Были введены понятия диаграммы потоков данных,

описывающей потоки данных внутри программы, и структурной

схемы, демонстрирующей взаимосвязь программных модулей. Были

изложены основные принципы техники нисходящего программиро-

вания.

Существенная часть главы была посвящена тому, как сде-

лать программу "дружественной пользователю": путем включения

в нее модулей, выдающих достаточную информацию о работе

программы. Присутствие модулей с подобными функциями упроща-

ет использование программ и повышает их эффективность.

Наконец, были описаны основные принципы работы с файла-

ми прямого доступа. Рассматривалось использование предиката

filepos для получения доступа к заданной позиции файла, а

также работа с записями фиксированной длины.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]