Энциклопедия Turbo Pascal. Главы 9-11 - Пример простого почтового списка
ОГЛАВЛЕНИЕ
Пример простого почтового списка
В качестве примера использования Turbo Access будет заново с применением его возможностей написана программа ведения простого почтового списка, разработанная в главе 2, которая использовала связанные ссылки. Во-первых, нам необходимо найти размер записи, используемой для хранения адресной информации, а затем вы примените программу SETCONST для вычисления соответствующих значений шести констант, требующихся для процедур Turbo Access.
Так как Turbo Access использует первые два байта в каждой записи в качестве флага индикации удаления, необходимо добавить поле целой переменной к исходной адресной записи. Кроме того, поля "предыдущий" и "следующий" больше не используются. Результирующая запись выглядит следующим образом:
type
address = record
status: integer; { используется Turbo Access }
name: string[30];
street: string[40];
city: string[20];
state: string[2];
zip: string[9];
end;
Длина в байтах поля adress, которая найдена, используя SizeOf, равна 108. Вам нужно будет данное число при выполнении программы SETCONST.PAS.
Программа SETCONST.PAS определяет значения констант, необходимых для Turbo Access. При запуске программы появляется экран, аналогичный показанному на рис.9-2, со значениями, принимаемыми по умолчанию. Руководство пользователя по инструментарию баз данных говорит, что для большинства применений вам необходимо изменить только длину записи и длину ключа, чтобы подстроиться под ваши особенности. Необходимо также изменить число записей, запоминаемых в базе данных, если оно превышает 10000. Размер страницы и размер стека страниц изменять не надо. Длина записи adress равна 108, так что сначала надо ввести это значение. В данном примере поле name будет использоваться в качестве ключа, поэтому значение 30 вводится как длина ключа. Клавишу RETURN нажать для оставшихся полей. Когда информация введена, SETCONT.PAS отображает экран, показанный на рис.9 -3.
При выходе из SETCONST.PAS вы можете автоматически создать соответствующую декларацию const. Декларация для программы
** 1 - рабочий лист задания констант Turbo Access, версия
1.10А *.
размер записи данных (байт) 200 20.
длина строки ключа (символов) 1.
размер базы данных (записей) 1000.
размер страницы (ключей) 2.
размер стека страниц (страниц) 1.
плотность (процент используемых элементов в средней странице)
50% 75% 100%
общее количество страниц индексного файл.
память, используемая для стека страниц (байт.
размер страницы индексного файла (байт.
размер индексного файла (байт.
размер файла данных (байт)
порядо.
максимальная высот.
среднее количество просмотров, необходимое для нахождения ключ.
среднее количество просмотров, удовлетворяемое стеком страни.
среднее количество просмотров на диске для нахождения ключа
нажмите ESC для завершения программы
Рис.9-2. Начальный экран SETCONST.PAS** Turbo Access constant determination worksheet, Version 1.10A
Data record size (bytes)
108 Key string Iength (characters)
30 Size of the database (records)
10000 Page size (keys)
24 Page stack size (pages)
10
Density (Percent of Items in use per average Page)50% 75% 100%
Total Index file pages
834 556 417 Memory used for page stack (bytes)
8430 8430 8430 Index file page size (bytes)
843 843 843 Index file size (bytes)
Data file size (bytes)
Order 12 12 12 MaxHeight
4 4 3 Average searches needed to find a key
3.71 3.19 2.90 Average searches satisfied by page stack
1.75 1.50 1.38 Average disk searches needed to find a key
1.96 1.69 1.52
ESC to end program
Рис.9-3. Экран SETCONST.PAS с вычисленными значениями: почтового списка показаны ниже. Комментарии даны автором.
Const
{данные константы сгенерированы программой SETCONST.PAS предоставляемой инструментарием баз данных.}MaxDataRecSize = 108;
MaxKeyLen = 30;
PageSize = 24;
Order = 12;
PageStackSize = 10;
MaxHeight = 4;
данные константы сгенерированы программой SETCONST.PAS, предоставляемой инструментарием баз данных.
С данной информацией и включенными необходимыми файлами Turbo Access первая часть программы почтового списка выглядит следующим образом:
program db_example;
Const
{данные константы сгенерированы программой SETCONST.PAS предоставляемой инструментарием баз данных.}MaxDataRecSize = 108;
MaxKeyLen = 30;
PageSize = 24;
Order = 12;
PageStackSize = 10;
MaxHeight = 4;
type
address = record
status: integer; {используется Turbo Access }
name: string[30];
street: string[40];
city: string[20];
state: string[2];
zip: string[9];
end;
{следующие файлы содержат процедуры баз данных}
{$i access.box} {основные процедуры баз данных}
{$i addkey.box} {добавить элементы }
{$i delkey.box} {удалить элементы }
{$i getkey.box} {поиск по дереву }
var
dbfile: DataFile;
ifile: IndexFile;
done: boolean;
В основном тексте программы, показанном далее, сначала инициализируется таблица индексов с помощью процедуры InitIndex. Далее либо открываются, либо создаются соответствующие файлы данных и индексный. Основной цикл программы аналогичен тому, который разработан в главе 2, и позволяет пользователю выбрать различные опции. При завершении файлы данных и индексный закрываются.
begin
InitIndex;
OpenFile(dbfile, 'mail.lst', SizeOf(address));
if not OK then
begin
WriteLn('creating new data file');
MakeFile(dbfile, 'mail.lst', SizeOf(address));
end;
OpenIndex(ifile, 'mail.ndx', 30, 0);
if not OK then
begin
WriteLn('creating new index file');
MakeIndex(ifile, 'mail.ndx', 30, 0);
end;
done:=false;
repeat
case MenuSelect of
'1': Enter;
'2': Remove;
'3': ListAll;
'4': Search;
'5': Update;
'6': done:=true;
end;
until done;
CloseFile(dbfile);
CloseIndex(ifile);
end.
Отметим, что больше не необходимо явно загружать и сохранять почтовый список: процедуры Turbo Access объявляют файлы автоматически.
Процедура Enter, показанная далее, вводит адресную информацию, запоминает ее в файле данных и помещает ключ в индексный файл. Отметим, что поле status каждой записи установлено в 0. По соглашению Turbo Access использует 0 для обозначения активной записи, а не нулевое значение для обозначения уничтоженных элементов.
temp: string[30];
info: address;
begin
done:=FALSE;
repeat
Write('Enter name:');
Read(info.name); WriteLn;
if Length(info.name)=0 then done:=TRUE
else
begin
Write('Enter street: ');
Read(info.street); WriteLn;
Write('Enter city: ');
Read(info.city); WriteLn;
Write('Enter state: ');
Read(info.state); WriteLn;
Write('Enter zip: ');
Read(info.zip); WriteLn;
info.status:=0; {сделать активной }
FindKey(ifile, recnum, info.name);
if not OK then {убедитесь, что нет дублированных
ключей }
begin
AddRec(dbfile, recnum, info);
AddKey(ifile, recnum, info.name);
end else WriteLn('Duplicate key ignored');
end;
until done;
end; {Enter}
Как вы видите, данная процедура осуществляет проверку на дублирование ключей. Так как дублированные имена не допускаются, процедура, во-первых, проверяет, соответствует ли новый ключ какому-либо уже существующему в файле. Если это так, то он игнорируется. Порядок вызова AddRec и AddKey критичен, так как переменная RecNum должна быть сначала установлена процедурой AddRec и затем запомнена процедурой AddKey (Помните, что номер записи файла данных связан с ключем в индексном файле и используется для последующего нахождения данных).
Процедура ListAll рассчитывает все содержимое почтового списка:
procedure ListAll;
{добавить адрес к списку}
procedure Enter;
var
done: boolean;
recnum: integer;
var
info: address;
len, recnum: integer;
begin
len: = filelen(dofile) -1;
for recnum:=1 to len do
begin
GetRec(dbfile, recnum, info);
{display if not deleter}
if info.status = 0 then display(info);
end;
end; {ListAll}
Процедура FileLen возвращает число записей активных или уничтоженных в файле данных, включая первую запись, которая зарезервирована для использования Turbo Access. Следовательно, действительное число пользовательских записей на единицу меньше. Кроме того, из-за того, что некоторые записи могут быть уничтожены, необходимо проверять поле status до отображения информации.
Поиск определенного адреса включает в себя поиск ключа в индексном файле с помощью процедуры FindKey. Когда ключ найден, возвращается соответствующий номер записи в файле данных и он используется процедурой GetRec для получения нужной информации. Процедура Search, показанная далее реализует данный подход:
{найти заданный элемент}
procedure Search;
var
name: string[30];
recnum: integer;
info: address;
begin
Write('Enter name: ');
ReadLn(name);
{найти ключ,если он существует}
FindKey(ifile, recnum, name);
if OK then { если найден }
begin
GetRec(dbfile, recnum, info);
{display if not deleter}
if info.status = 0 then Display(info);
end else WriteLn('not found');
end; {Search}
Наконец, модификация существующей записи предполагает, что вы должны сначала найти запись, считать ее, модифицировать и записать обратно в файл данных. Процедура Update иллюстрирует простой метод обновления, в котором пользователь должен ввести заново всю информацию. Более сложные подходы требуют перевода только изменяемых полей.
{ изменение адреса в списке, исключая поле имени }
procedure Update;
var
done: boolean;
recnum: integer;
temp: string[30];
info: address;
begin
Write('Введите имя: ');
Read(info.name); WriteLn;
FindKey(ifile, recnum, info.name);
if OK then
begin
Write('Введите улицу: )';
Read(info.street); WriteLn;
Write('Введите город: ');
Read(info.city); WriteLn;
Write('Введите штат: ');
Read(info.state); WriteLn;
Write('Введите индекс: ');
Read(info.zip); WriteLn;
info.status:=0; {сделать активной}
PutRec(dbfile, recnum, info);
end else WriteLn('ключ не найден');
end; {Update}