Энциклопедия Turbo Pascal. Главы 9-11
Страница 9. Пример простого почтового списка


Пример простого почтового списка

     В качестве примера использования 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    200
     длина строки ключа (символов)                 10
     размер базы данных (записей)               10000
     размер страницы (ключей)                      24
     размер стека страниц (страниц)                10
     плотность (процент используемых элементов в средней странице)
                                                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}

     Целиком программа,  использующая 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;

     function MenuSelect:char; {возврат  пользовательского
                             выбора }

     var
       ch:char;
     begin
       WriteLn('1.       ');
       WriteLn('2. Удалить имя      ');
       WriteLn('3. Отобразить список');
       WriteLn('4. Обновление       ');
       WriteLn('5. Поиск по имени   ');
       WriteLn('6. Выход            ');
       repeat
         WriteLn;
         Write('Введите ваш выбор:');
         Read(ch); ch:=UpCase(ch); WriteLn;
         until (ch>='1') and (ch<='6');
         MenuSelect:=ch;
       end; {MenuSelect}

     {добавить адрес к списку}
       procedure Enter;
       var
         done: boolean;
         recnum: integer;
         temp: string[30];
         info: address;
       begin
         done:=FALSE;
         repeat
           Write('Введите имя: ');
           Read(info.name); WriteLn;
           if Length(info.name)=0 then done:=TRUE

         else

         begin
         Write('Введите улицу: ');
         Read(info.street); WriteLn;
         Write('Введите город: ');
         Read(info.city); WriteLn;
         Write('Введите штат: ');
         Read(info.state); WriteLn;
         Write('Введите индекс: ');
         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('Дублированный ключ игнорирован');
         end;
       until done;
     end; {Enter}

     { изменение адреса в списке, исключая поле имени }
     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}

     {удалить адрес из списка }

     procedure Remove;
     var
       recnum: integer;
       name: string[30];
       info: address;
     begin
       Write('Введите имя для удаления : ');
       Read(name); WriteLn;
       FindKey(ifile, recnum, name);
       if OK then
       begin
         DeleteRec(dbfile, recnum);
         DeleteKey(ifile, recnum, name);
       end else WriteLn('Не найдено');
     end; {Remove}

     procedure Display(info: address);
     begin
       WriteLn(info.name);
       WriteLn(info.street);
       WriteLn(info.city);
       WriteLn(info.state);
       WriteLn(info.zip); WriteLn;
     end; {Display}

     procedure ListAll;
     var
       info: address;
       len, recnum: integer;
     begin
       len := fileLen(dbfile) -1;
       for recnum:=1 to len do
       begin
         GetRec(dbfile, recnum, info);
         {отобразить,  если не уничтожен}
         if info.status = 0 then display(info);
       end;
     end; {ListAll}

     {Найти заданный элемент }
     procedure Search;
     var
       name: string[30];
       recnum: integer;
       info: address;
     begin
       Write('Введите имя: ');
       ReadLn(name);

       {найти ключ,  если существует}
       FindKey(ifile, recnum, name);
       if OK then
       begin
         GetRec(dbfile, recnum, info);
         {отобразить,  если не уничтожен}
         if info.status = 0 then Display(info);
       end else WriteLn('не найден');
     end; {Search}

     begin
       InitIndex;
       OpenFile(dbfile, 'mail.lst', SizeOf(address));
       if not OK then
       begin
         WriteLn('Cоздание нового файла');
         MakeFile(dbfile, 'mail.lst', SizeOf(address));
       end;
       OpenIndex(ifile, 'mail.ndx', 30, 0);
       if not OK then
       begin
         WriteLn('Cоздание нового файла ');
         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.

 
Следующая статья »