Опубликован: 06.12.2004 | Доступ: свободный | Студентов: 1179 / 142 | Оценка: 4.76 / 4.29 | Длительность: 20:58:00
ISBN: 978-5-9556-0021-5
Лекция 9:

Технологические интерфейсы

Функции для работы с простыми базами данных

Описываемые ниже функции полезны для реализации "игрушечных" баз данных при изготовлении прототипов приложений. Нет и речи о поддержке многопользовательского режима. Ключ в записи может быть только один. Суммарная длина ключа и данных (точнее, всех ключей, имеющих один хэш-код, и ассоциированных с ними данных) не должна превышать 1023 байта и т.д. и т.п.

Набор стандартизованных функций "традиционно минимален" (см. листинг 9.10). Базу данных можно открыть ( dbm_open() ) и закрыть ( dbm_close() ), выбрать ( dbm_fetch() ), сохранить ( dbm_store() ) и удалить ( dbm_delete() ) запись по ключу, перебрать имеющиеся в базе ключи ( dbm_firstkey(), dbm_nextkey() ), опросить статус ошибки ( dbm_error() ) и очистить его ( dbm_clearerr() ).

#include <ndbm.h>

DBM *dbm_open (const char *file, 
    int open_flags, mode_t file_mode);

void dbm_close (DBM *db);

datum dbm_fetch (DBM *db, datum key);

int dbm_store (DBM *db, datum key, 
    datum content, int store_mode);

int dbm_delete (DBM *db, datum key);

datum dbm_firstkey (DBM *db);

datum dbm_nextkey (DBM *db);

int dbm_error (DBM *db);

int dbm_clearerr (DBM *db);
Листинг 9.10. Описание функций для работы с простыми базами данных.

Функцию dbm_open() можно считать аналогом open(), только в роли возвращаемого в качестве результата дескриптора базы данных выступает указатель на объект типа   DBM (структура последнего скрыта от приложения), база хранится в двух файлах – file.dir и file.pag, ее нельзя открыть только на запись, а применение флага O_APPEND ведет к неспецифицированным последствиям. В случае ошибки результат вызова dbm_open() равняется (DBM *) NULL.

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

void   *dptr;   
    /* Указатель на прикладные данные  */
size_t  dsize;  
    /* Размер прикладных данных        */

Функция dbm_fetch() служит для выборки   записи по ключу   key. Если таковая отсутствует или обнаруживается ошибка, то в возвращаемом объекте типа   datum элемент dptr равняется пустому указателю.

Функция dbm_store() позволяет поместить данные, заданные аргументом   content, в базу. Аргумент   store_mode определяет способ сохранения новых данных. Если в базе уже есть запись с заданным ключом   key, то в режиме DBM_REPLACE новая запись замещает старую, а в режиме DBM_INSERT она (новая запись ) игнорируется (и результат вызова равняется единице). Если записи с ключом   key в базе нет, новая запись добавляется к базе.

Функция dbm_delete() предназначена для удаления данных и ключа   key.

Нормальным результатом функций dbm_store() и dbm_delete() является нуль; в случае ошибки возвращается отрицательное значение.

Функция dbm_nextkey() является итератором по ключам, хранящимся в базе, а dbm_firstkey() инициализирует этот итератор, возвращая первый ключ. При завершении перебора и при наличии ошибок возвращается объект типа   datum с пустым указателем в качестве значения элемента dptr. Если по ходу итераций содержимое базы менялось (вызывались функции dbm_store() и/или dbm_delete() ), перебор ключей нужно начинать заново.

Функция dbm_error() возвращает ненулевое значение при установленном статусе ошибки, функция dbm_clearerr() делает статус "безошибочным". Таким образом, вся диагностика по сути сводится к одному биту, интерпретировать который должно приложение.

Несмотря на "игрушечность" описанного интерфейса, он находит определенное применение на Unix-системах. В качестве примера рассмотрим программу, которая распечатывает содержимое базы данных   aliases, расположенной в каталоге   /etc/mail на SPARC -станции (см. листинг 9.11).

/* * * * * * * * * * * * * * * * * * * * * * * * */
/* Программа перебирает все ключи в базе данных  */
/* и выдает ассоциированную с ними информацию.   */
/* Предполагается, что ключи и данные – текстовые*/
/* * * * * * * * * * * * * * * * * * * * * * * * */

#include <ndbm.h>
#include <stdio.h>
#include <fcntl.h>

int main (int argc, char *argv []) {
    DBM *dbdes;         /* Дескриптор открытой базы  */
    datum ckey;         /* Текущий ключ              */
    datum cdat;         /* Текущие данные            */
    int nkeys = 0;      /* Число ключей              */

    if (argc != 2) {
        fprintf (stderr, "Использование: %s имя_базы\n", 
                    argv [0]);
        return (1);
    }

    if ((dbdes = dbm_open (argv [1], 
            O_RDONLY, 0777)) == (DBM *) NULL) {
        fprintf (stderr, "Не удалось открыть базу данных %s\n", 
                    argv [1]);
        return (2);
    }

    for (ckey = dbm_firstkey (dbdes); ckey.dptr != NULL;
            ckey = dbm_nextkey (dbdes)) {
        nkeys++;
        printf ("Длина ключа номер %d: %d\n", nkeys, 
                    ckey.dsize);
        printf ("Ключ номер %d: %s\n", nkeys, ckey.dptr);

        if (cdat = dbm_fetch (dbdes, ckey), 
                cdat.dptr != NULL) {
            printf ("Длина данных для ключа номер %d: %d\n", 
                        nkeys, cdat.dsize);
            printf ("Данные для ключа номер %d: %s\n", nkeys, 
                        cdat.dptr);
        } else {
            fprintf (stderr, "Отсутствуют данные для "
                                    "ключа номер %d\n", nkeys);
        }
    }

    printf ("Число ключей в базе: %d\n", nkeys);

    dbm_close (dbdes);

    return 0;
}
Листинг 9.11. Пример применения функций для работы с простыми базами данных.

Результаты работы этой программы могут выглядеть так, как показано на листинге 9.12.

Длина ключа номер 1: 16
Ключ номер 1: YP_LAST_MODIFIED
Длина данных для ключа номер 1: 10
Данные для ключа номер 1: 0898782331
Длина ключа номер 2: 14
Ключ номер 2: mailer-daemon
Длина данных для ключа номер 2: 11
Данные для ключа номер 2: postmaster
Длина ключа номер 3: 14
Ключ номер 3: YP_MASTER_NAME
Длина данных для ключа номер 3: 3
Данные для ключа номер 3: t41
Длина ключа номер 4: 11
Ключ номер 4: postmaster
Длина данных для ключа номер 4: 5
Данные для ключа номер 4: root
Длина ключа номер 5: 7
Ключ номер 5: nobody
Длина данных для ключа номер 5: 10
Данные для ключа номер 5: /dev/null
Длина ключа номер 6: 2
Ключ номер 6: @
Длина данных для ключа номер 6: 2
Данные для ключа номер 6: @
Число ключей в базе: 6
Листинг 9.12. Возможные результаты выполнения программы, применяющей функции для работы с простыми базами данных.