dbm基本概念
所有版本的 Linux 以及大多数的 UNIX 版本都随系统带有一个基本的、但却非常高效的数据存储例程集,它被称为dbm数据库。dbm 数据库适合存储相对比较静态的索引化数据。一些数据库纯粹主义者可能会认为 dbm 根本算不上是一个数据库,充其量就是一个索引化的文件存储系统。但 X/Open 规范把 dbm 看做是一个数据库。
对于不同的 Linux 发行版本,编译使用 ndbm 库的源文件所需要的包含库和链接库略有不同,所以,虽然安装了 gdbm 和 ndbm兼容库,但可能还需要通过实验来发现人员和编译这些源文件。最常见的情况是,系统已经安装了 gdbm ,并且它在默认情况下就支持了 ndbm 兼容模式。在这种情况下,需要执行如下操作。
- 在 C 源文件中包含头文件 nbdm.h。
- 使用编译行选项 -I/usr/include/gdbm 包含头文件目录 /usr/include/gdbm。
- 使用编译行选项 -lgdbm 链接 gdbm库。
程序中用到的 dbm数据库函数:
- DBM *dbm_open( const char *filename, int file_open_flags, mode_t file mode );
这个函数是用来打开已有的数据库,也可以用来创建新数据库。filename 参数是一个基本文件名。它不包含.dir 或 .pag后缀。
其余的参数和 open 函数的第二个和第三个参数一样。第二个参数控制数据库的读、写或读/写权限。如果要创建一个新的数据库,这个标志必须与 O_CREAT 进行二进制或才允许文件被创建。第三个参数指定将被创建的文件的初始权限。
dbm_open 返回一个指向 DBM 类型的指针。它被用于所有后续对数据库的访问。如果失败,它将返回 (DBM *) 0。 - int dbm_store( DBM *database_descriptor, datum key, datum content, int store_mode );
这个函数用来把数据存储到数据库中。所有数据在存储时都必须有一个唯一的索引。为了定义想要存数的数据和用来引用它的索引,必须设置两个 datum 类型的参数:一个用于引用索引,一个用于实际数据。最后一个参数 store_mode 用于控制当试图以一个已有的关键字来存储数据时会发生的情况。如果它被设置为 dbm_insert ,存储操作将失败并且 dbm_store 返回1.如果它被设置为 dbm_replace ,则新数据将覆盖已有数据并且 dbm_store 返回0.当发生其他错误时,函数将返回一个负值。 - datum dbm_fetch( DBM *database_descriptor, datum key );
函数用于从数据库中检索数据。它使用一个先前 dbm_open 调用返回的指针和一个指向关键字的 datum 类型结构作为参数。它返回一个 datum 类型的结构。如果在数据库中找到与这个关键字关联的数据,返回的 datum 结构的 dptr 和 dsize 成员的值将被设为相应数据的值。如果没有找到关键字,dptr将被设置为null。 - void dbm_close( DBM *database_descriptor );
这个函数关闭用dbm_open 打开的数据库。它的参数是先前 dbm_open 调用返回的 dbm 指针。 - int dm_delete( DBM *database_descriptor, datum key );
函数用来从数据库中删除数据项。与dbm_fetch一样,它也使用一个指向关键字的 datum 类型结构作为其参数,但不同的是,它是用于删除数据而不是用于检索数据。它在成功时返回0. - datum dbm_firstkey( DBM *database_descriptor );
datum dbm_nextkey( DBM *database_descriptor );
这两个函数一半承兑使用,来对数据库中的所有关键字进行扫描。
实验完整C代码
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <ndbm.h> #include <string.h> #define TEST_DB_FILE "/tmp/dbm2_test" #define ITEMS_USED 3 typedef struct test_data { char misc_chars[15]; int any_integer; char more_chars[21]; }test_data; int main() { test_data items_to_store[ITEMS_USED]; //定义一个test_data结构体数组 test_data item_retrieved; //定义一个结构体 char key_to_use[20]; //用来存储关键字字符串 int i, result; datum key_datum; //创建关键字 datum data_datum; DBM *dbm_ptr; dbm_ptr = dbm_open( TEST_DB_FILE, O_RDWR | O_CREAT, 0666 ); if( NULL == dbm_ptr ) { fprintf( stderr, "Failed to open database\n"); exit( EXIT_FAILURE ); } memset( items_to_store, '\0', sizeof(items_to_store) ); //将items_to_store数组的内存空间全部填充'\0'字符 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" ); //为每一个数据建立一个供以后引用的关键字。本例中为每个字符串的首字母+整形数字 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(test_data); result = dbm_store( dbm_ptr, key_datum, data_datum, DBM_REPLACE ); if( 0 != result ) { fprintf( stderr, "dbm_store failed on key %s\n", key_to_use ); exit( 2 ); } } //检索新存入的数据 sprintf( key_to_use, "bu%d", 13); //本例检测items_to_store[2]中的数据 key_datum.dptr = key_to_use; key_datum.dsize = strlen( key_to_use ); data_datum = dbm_fetch( dbm_ptr, key_datum ); if( 0 != data_datum.dptr ) { printf("Data retrieved\n"); memcpy( &item_retrieved, data_datum.dptr, data_datum.dsize ); printf( "Retrieved item - %s %d %s\n", item_retrieved.misc_chars, item_retrieved.any_integer, item_retrieved.more_chars ); } else printf( "No data found for key %s\n", key_to_use ); //删除该项数据 sprintf( key_to_use, "bu%d", 13 ); key_datum.dptr = key_to_use; key_datum.dsize = strlen( key_to_use ); if( 0 == dbm_delete( dbm_ptr, key_datum) ) printf( "Data with key %s deleted\n", key_to_use ); else printf( "Nothing deleted foe key %s\n", key_to_use ); for( key_datum = dbm_firstkey( dbm_ptr ); key_datum.dptr; key_datum = dbm_nextkey( dbm_ptr ) ) { data_datum = dbm_fetch( dbm_ptr, key_datum ); if( NULL != data_datum.dptr ) { printf("Data retrieved\n"); memcpy( &item_retrieved, data_datum.dptr, data_datum.dsize ); printf( "Retrieved item - %s %d %s\n", item_retrieved.misc_chars, item_retrieved.any_integer, item_retrieved.more_chars ); } else printf( "No data found for key %s\n", key_to_use ); } dbm_close( dbm_ptr ); exit( EXIT_SUCCESS ); }
我自己机器上的编译命令为:cc -I/usr/includegdbm -lgdbm dbm2.c -o dbm2
源代码保存文件名为:dbm2.c
程序运行结果