Книга: Основы программирования в Linux

Функции доступа dbm

Функции доступа dbm

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

#include <ndbm.h>
DBM *dbm_open(const char* filename, int file_open_flags,
 mode_t file_mode);
int dbm_store(DBM *database_descriptor, datum key, datum content,
 int store_mode);
datum dbm_fetch(DBM* database descriptor, datum key);
void dbm_close(DBM *database descriptor);

dbm_open

Эта функция применяется для открытия имеющихся баз данных и для создания новых баз данных. Аргумент filename — имя файла базы данных без расширения dir или pag.

Остальные параметры такие же, как второй и третий параметры функции open, с которой вы встречались в главе 3. Вы можете использовать те же директивы #define. Второй аргумент управляет возможностью чтения базы данных, записью в нее или обеими операциями. Если создается новая база данных, флаги должны быть двоичными O_READ с O_CREAT, чтобы разрешить создание файлов. Третий аргумент задает начальные права доступа к файлам, которые будут созданы.

Функция dbm_open возвращает указатель на тип DBM. Он применяется во всех последующих обращениях к базе данных. В случае аварийного завершения возвращается (DBM*)0.

dbm_store

Эту функцию применяют для ввода данных в базу данных. Как упоминалось ранее, все данные должны сохраняться с уникальным индексом. Для определения данных, которые вы хотите сохранить, и индекса, используемого для ссылки на них, следует задать два типа datum: один для ссылки на индекс, а другой — на реальные данные. Последний параметр store_mode управляет действиями, совершаемыми при попытке сохранить какие-либо данные с применением ключа, который уже существует. Если установлено значение параметра dbm_insert, сохранение завершается аварийно и функция dbm_store возвращает 1. Если установлено значение параметра dbm_replace, новые данные заменяют существующие и dbm_store возвращает 0. При возникновении других ошибок функция dbm_store возвращает отрицательные числа.

dbm_fetch

Подпрограмма dbm_fetch применяется для извлечения данных из базы данных. Она принимает в качестве параметра указатель dbm, возвращенный предшествующим вызовом функции dbm_open и тип datum, который должен быть задан как указатель на ключ. Тип datum возвращается, если данные, относящиеся к используемому ключу, найдены в базе данных, возвращаемая структура datum будет иметь значения dptr и dsize, ссылающиеся на возвращенные данные. Если ключ не найден, dptr будет равен null.

Примечание

Важно помнить, что функция dbm_fetch возвращает только параметр типа datum, содержащий указатель на данные. Реальные данные могут находиться в локальной области памяти внутри библиотеки dbm и должны быть скопированы в переменные программы перед дальнейшими вызовами функций dbm.

dbm_close

Эта подпрограмма закрывает базу данных, открытую функцией dbm_open, и должна получить указатель DBM, возвращенный предшествующим вызовом dbm_open.

А теперь выполните упражнение 7.12.

Упражнение 7.12. Простая база данных dbm

Познакомившись с основными функциями базы данных dbm, теперь вы знаете, как написать вашу первую программу для работы с dbm (dbm1.c). В этой программе применяется структура, названная test_data.

1. Первыми представлены файлы #include, директивы #define, функция main и объявление структуры test_data:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <ndbm.h>
/* В некоторых системах вам нужно заменить вышестоящую строку строкой #include <gdbm-ndbm.h>*/
#include <string.h>
#define TEST_DB_FILE "/tmp/dbm1_test"
#define ITEMS_USED 3
struct test_data {
 char misc_chars[15];
 int any_integer;
 char more_chars[21];
};
int main() {

2. В функции main задайте элементы структур items_to_store и items_received, строку key и типы datum:

 struct test_data items_to_store[ITEMS_USED];
 struct test_data item_retrieved;
 char key_to_use[20];
 int i, result;
 datum key_datum;
 datum data_datum;
 DBM *dbm_ptr;

3. Объявив указатель на структуру типа DBM, откройте вашу тестовую базу данных для чтения и записи, создав ее при необходимости:

 dbm_ptr = dbm_open(TEST_DB_FILE, O_RDWR | O_CREAT, 0666);
 if (!dbm_ptr) {
  fprintf (stderr, "Failed to open databasen");
  exit(EXIT_FAILURE);
 }

4. Теперь добавьте данные в структуру items_to_store:

 memset(items_to_store, '', sizeof(items_to_store));
 strcpy(items_to_store[0].misc_chars, "First! ");
 items_to_store[0].any_integer = 47;
 strcpy(items_to_store[0].more_chars, "foo");
 strcpy(items_to_store[1].misc_chars, "bar");
 items_to_store[1].any_integer = 13;
 strcpy(items_to_store[1].more_chars, "unlucky? ");
 strcpy(items_to_store[2].misc_chars, "Third");
 items_to_store[2].any_integer = 3;
 strcpy(items_to_store[2].more_chars, "baz");

5. Для каждого элемента необходимо сформировать ключ для будущих ссылок в виде первой буквы каждой строки и целого числа. Этот ключ затем будет обозначен key_datum, когда data_datum сошлется на элемент items_to_store. Далее вы сохраняете данные в базе данных:

 for (i = 0; i < ITEMS_USED; i++) {
  sprintf(key_to_use, "%c%c%d",
   items_to_store[i].misc_chars[0], items_to_store[i].more_chars[0], items_to_store[i].any_integer);
  key_datum.dptr = (void*)key_to_use;
  key_datum.dsize = strlen(key to_use);
  data_datum.dptr = (void*)&items_to_store[i];
  data_datum.dsize = sizeof(struct.test_data);
  result = dbm_store(dbm_ptr, key_datum, data_datum, DBM_REPLACE);
  if (result != 0) {
   fprintf(stderr, "dbm_store failed on key %sn", key_to_use);
   exit(2);
  }
 }

6. Далее посмотрите, сможете ли вы извлечь эти новые данные, и в заключение следует закрыть базу данных:

 sprintf(key_to_use, "bu%d", 13);
 key_datum.dptr = key_to_use;
 key_datum.dsize = strlen(key_to_use);
 data_datum = dbm_fetch(dbm_ptr, key_datum);
 if (data_datum.dptr) {
  printf("Data retrievedn");
  memcpy(&item_retrieved, data_datum.dptr, data_datum.dsize);
  printf("Retrieved item — %s %d %sn", item_retrieved.misc_chars,
   item_retrieved.any_integer, item_retrieved.more_chars);
 } else {
  printf("No data found for key %sn", key_to_use);
 }
 dbm_close(dbm_ptr);
 exit(EXIT_SUCCESS);
}

Когда вы откомпилируете и выполните программу, вывод будет следующим:

$ gcc -о dbm1 -I/usr/include/gdtm dbm1.с -lgdbm
$ ./dbm1
Data retrieved
Retrieved item — bar 13 unlucky?

Вы получите приведенный вывод, если база данных gdbm установлена в режиме совместимости. Если компиляция не прошла, возможно, вам придется изменить директиву include, как показано в файле, для использования заголовочного файла gdbm-ndbm.h вместо файла ndbm.h и задать в строке компиляции библиотеку совместимости перед основной библиотекой, как показано в следующей строке:

$ gcc -о dbm1 -I/usr/include/gdbm dbm1.с -lgdbm_compat -lgdbm

Как это работает

Сначала вы открываете базу данных, при необходимости создавая ее. Затем вы заполняете три элемента структуры items_to_store, чтобы использовать их как тестовые данные. Для каждого из трех элементов вы создаете индексный ключ. Чтобы он оставался простым, используйте первые символы каждой из двух строк плюс сохраненное целое.

Далее вы задаете две структуры типа datum, одну для ключа и другую для сохраняемых данных. Сохранив три элемента в базе данных, вы конструируете новый ключ и настраиваете структуру типа datum так, чтобы она указывала на него. Затем вы применяете данный ключ для извлечения данных из базы данных. Убедитесь в успехе, проверив, что dptr в возвращенном datum не равен null. Получив подтверждение, вы можете копировать извлеченные данные (которые могут храниться внутри библиотеки dbm) в вашу собственную структуру, применяя возвращенный размер dbm_fetch (если этого не сделать, при наличии данных переменного размера вы можете скопировать несуществующие данные). В заключение извлеченные данные выводятся на экран, чтобы продемонстрировать корректность их извлечения.

Оглавление книги


Генерация: 8.370. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз