现在的位置: 首页 > 数据库 > 正文

一个简单的dbm数据库的实验—–dbm打开 存储 检索 删除 扫描操作的C代码

2019年04月24日 数据库 ⁄ 共 4228字 ⁄ 字号 评论关闭

dbm基本概念

所有版本的 Linux 以及大多数的 UNIX 版本都随系统带有一个基本的、但却非常高效的数据存储例程集,它被称为dbm数据库。dbm 数据库适合存储相对比较静态的索引化数据。一些数据库纯粹主义者可能会认为 dbm 根本算不上是一个数据库,充其量就是一个索引化的文件存储系统。但 X/Open 规范把 dbm 看做是一个数据库。

对于不同的 Linux 发行版本,编译使用 ndbm 库的源文件所需要的包含库和链接库略有不同,所以,虽然安装了 gdbm 和 ndbm兼容库,但可能还需要通过实验来发现人员和编译这些源文件。最常见的情况是,系统已经安装了 gdbm ,并且它在默认情况下就支持了 ndbm 兼容模式。在这种情况下,需要执行如下操作。

  1. 在 C 源文件中包含头文件 nbdm.h。
  2. 使用编译行选项 -I/usr/include/gdbm 包含头文件目录 /usr/include/gdbm。
  3. 使用编译行选项 -lgdbm 链接 gdbm库。

程序中用到的 dbm数据库函数:

  1.  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。

  2. 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.当发生其他错误时,函数将返回一个负值。

  3. datum dbm_fetch( DBM *database_descriptor, datum key );
    函数用于从数据库中检索数据。它使用一个先前 dbm_open 调用返回的指针和一个指向关键字的 datum 类型结构作为参数。它返回一个 datum 类型的结构。如果在数据库中找到与这个关键字关联的数据,返回的 datum 结构的 dptr 和 dsize 成员的值将被设为相应数据的值。如果没有找到关键字,dptr将被设置为null。

  4. void dbm_close( DBM *database_descriptor );
    这个函数关闭用dbm_open 打开的数据库。它的参数是先前 dbm_open 调用返回的 dbm 指针。

  5. int dm_delete( DBM *database_descriptor, datum key );
    函数用来从数据库中删除数据项。与dbm_fetch一样,它也使用一个指向关键字的 datum 类型结构作为其参数,但不同的是,它是用于删除数据而不是用于检索数据。它在成功时返回0.

  6. 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

程序运行结果

  

抱歉!评论已关闭.