Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi / песни о паскале.pdf
Скачиваний:
62
Добавлен:
26.03.2016
Размер:
5.16 Mб
Скачать

Глава 29 Читайте по-новому

Отдохнув на экскурсии, с новой силой набросимся на файлы, — ведь именно там хранятся наши данные. Научимся извлекать из файлов числа.

Полицейская база данных, версия 1

Одна из первых наших программ исполняла должность электронного часового, охранявшего секретный объект. Теперь поможем другой силовой структуре — дорожной полиции.

Долг автоинспектора — в числе прочего — поиск угнанных автомобилей. Работа нехитрая: заприметив подозрительный автомобиль, инспектор сверяет его номер со своей картотекой. И, если номер в картотеке найдется, принимает меры к задержанию автомобиля и поимке преступника. В отличие от часового, который помнит всего один пароль, полицейский роется в пухлой картотеке с тысячами номеров. В этом и состояла его главная трудность, пока не явились компьютерные

базы данных.

Базы данных (сокращенно БД) — кто не слышал о них? На ум приходят базы данных Пентагона, ЦРУ и налоговой инспекции. Да, эти чудовищные БД впечатляют! Впрочем, чтобы увидеть базу данных, не спешите потрошить Пентагон. Вот расписание поездов, программа телепередач или классный журнал,

— всё это простые базы данных. В конце концов, любая БД — это организованное хранилище данных, приспособленное для удобного поиска информации. Нам тоже по силам создать несложную полицейскую базу данных.

Соорудим такую базу с номерами угнанных автомобилей, и воспользуемся для этого текстовым файлом. Допустим, что номера автомобилей — это числа; тогда база данных — это файл с напечатанными в столбик номерами: каждая строка файла содержит один номер. Номера могут следовать в любом порядке, например:

123

325

234

11

Такой файл можно напечатать любым редактором текста, в том числе и встроенным в IDE. Мы так и поступим: создайте новый файл, впечатайте в него десяток-другой пришедших на ум номеров и сохраните в рабочей папке под именем «Police.txt». Окно с этим файлом пока не закрывайте, оно ещё пригодится.

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

191

Глава 29 Читайте по-новому

доброго дела напишем программу для поиска номера в этой базе. Такая программа должна работать как часовой, запрашивая у полицейского номер автомобиля и сообщая о том, содержится ли этот номер в БД. Признаком выхода из программы будет ввод нулевого номера.

Итак, приступим к программе P_29_1. Схема главной программы ясна из вышесказанного. Выносить заключение об автомобиле будет функция булевого типа, принимающая два параметра: файловую переменную, связанную с нашей БД, и номер искомого автомобиля. Если номер в базе данных обнаружится, функция вернет значение TRUE. Ввиду простоты алгоритма не буду рисовать блок-схему. Если чуете в себе силу, напишите программу сами, и, после некоторых мучений, сравните с тем, что показано ниже.

{ P_29_1 – Полицейская база данных, версия 1 }

function FindNumber(var aFile: text; aNumber: integer): boolean; var N: integer; { текущий номер в БД }

begin

FindNumber:= false;

{ на случай, если файл пуст }

Reset(aFile);

{ позицию чтения устанавливаем в начало файла }

N:=0;

 

{ в начале цикла задаем несуществующий номер }

{ читаем номера из файла, пока НЕ конец файла И номер НЕ найден }

while not Eof(aFile) and (N<>aNumber) do begin

 

Readln(aFile, N);

 

 

 

FindNumber:= (N=aNumber);

{ true, если номер нашелся }

end;

 

 

 

 

 

end;

 

 

 

 

 

var F: text;

Num: integer;

 

 

begin {----- Главная программа -----}

 

 

Assign(F, 'Police.txt');

 

 

repeat

 

 

 

 

 

Write('Укажите номер автомобиля: ');

Readln(Num);

if FindNumber(F, Num)

 

 

 

then Writeln('Эта машина в розыске, хватайте его!')

 

else Writeln('Пропустите его');

 

until Num=0; { 0 – признак завершения программы} Close(F);

end.

Поясню некоторые моменты. В начале главной программы файловая переменная F связывается с файлом «Police.txt». Далее следует хорошо знакомая конструкция REPEAT—UNTIL с проверкой условия в конце цикла.

192

Глава 29 Читайте по-новому

Самое интересное скрыто внутри функции FindNumber (от Find — «искать», Number — «номер»). Туда передаются два параметра, один из которых — файловая переменная. Обратите внимание на способ её передачи: файловая переменная передается по ссылке (в заголовке указано слово VAR). И никак иначе файловую переменную не передают! Со временем узнаете причину, а пока просто запомните: файловые переменные передают внутрь процедур и функций только по ссылке! Следовательно, параметр aFile ссылается на глобальную переменную F.

А к чему здесь приставки «a» перед именами параметров: aFile, aNumber? Или это тоже правило языка? Нет, друзья, это всего лишь уловка программистов, которую полезно перенять. Чем сложнее будут ваши программы, тем гуще будут заселены разного рода переменными и параметрами. Во избежание путаницы лучше учредить разумную систему обозначений. Большинство программистов используют для систематизации имен так называемые префиксы или приставки. Например, для параметров (аргументов) процедур и функций применяют префикс «a» (от слова «argument»). Помеченные таким образом параметры уже не спутаешь с локальными или глобальными переменными.

Теперь заглянем внутрь функции FindNumber. В первой строке результату функции присваивается значение FALSE. И это оправдано, поскольку значение функции обязательно должно быть определено, а в случае, если файл БД окажется пустым, этого не случится, поскольку следующий далее цикл WHILE не будет выполняться.

Поиск номера должен начинаться с начала файла. Оператор Reset внутри функции как раз и возвращает позицию чтения на линию старта. Будьте спокойны

— файл от этого не пострадает, открывать его для чтения можно без ограничений!

Теперь взгляните на условие цикла WHILE, — оно чуть сложнее тех, к которым мы привыкли.

while not Eof(aFile) and (N<>aNumber)

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

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

FindNumber:= (N=aNumber);

{ true, если номер нашелся }

Левая его часть — это идентификатор функции, а правая (в скобках) — оператор сравнения двух чисел. Оператор сравнения дает булев результат, равный TRUE, если числа совпадают. Скобки в правой части здесь не нужны, но я поставил их для наглядности. Приведенный выше оператор можно было бы заменить таким.

193

Глава 29 Читайте по-новому

if N=aNumber

then FindNumber:= true

else FindNumber:= false;

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

Итак, прежде чем двинуться дальше, не поленитесь проверить эту программу.

Полицейская база данных, версия 2

Теперь слегка изменим расположение чисел в файле «Police.txt». Вместо одного числа в строке, напечатайте в каждой по нескольку чисел, разделив их одним или несколькими пробелами, например:

123 234 325

223 240

845 431 205

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

Переключитесь в окно нашей базы данных «Police.txt» и внесите необходимые изменения. Сохранить файл не забыли? Теперь запустите программу и проверьте её на номерах из этого файла. При должном внимании вы обнаружите, что программа правильно находит только числа, начинающие строку, например 123, 223 и 845. Все последующие номера в строке программа не замечает, хотя и аварийных сообщений не выдает. В чем же дело?

Причина — в процедуре Readln. До сих пор мы пользовались ею для чтения строк и горя не знали. Но числа — иное дело. Приглашаю вас мысленно проследить за позицией чтения в ходе просмотра нашей БД (рис. 66). Невидимые признаки конца строки обозначены на рисунке условными символами Eoln (это пара символов с кодами 13 и 10).

194

Глава 29 Читайте по-новому

Reset

123

234

325

Eoln

 

Readln

223

240

Eoln

 

Readln

845

431

205

Eoln

Рис. 66 – Продвижение позиции чтения процедурой Readln

После того, как Reset установит позицию чтения в начало файла, процедура Readln прочитает первое число. Чтение идет цифра за цифрой, пока не встретится любой символ, отличный от неё, например, пробел или конец строки. Проглотив таким образом первое число, процедура Readln продвинет позицию чтения в начало следующей строки, пропуская при этом всё, что расположено до конца текущей. Вот в чем дело! Не зря к названию процедуры прилепился суффикс «LN» (сокращенное от Line — «строка»). Источник проблемы ясен: процедура Readln не подходит для чтения нескольких чисел в строке. Где же выход?

Спокойно, друзья, в Паскале заготовлено всё! Познакомьтесь с процедурой Read (без суффикса), которая почти не отличается от своей «сестренки» — принимает те же параметры и читает те же данные. Но при этом самовольно не продвигает позицию чтения в начало следующей строки. А нам того и нужно! Продвижение позиции чтения процедурой Read показано на рис. 67.

Read

Read

Reset

 

123

234

223

240

Read

 

845

431

325 Eoln

Eoln

205 Eoln

Рис. 67 – Продвижение позиции чтения процедурой Read

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

195

Соседние файлы в папке delphi