管理我的数据 — GDBM

前言:
GDBM(GNU database manager)是一套简单的资料管理程序。最新版本是gdbm-1.10,在大部分的UNIX和Linux系统中已经默认提供,如果没有提供,也可以到官方主页http://www.gnu.org.ua/software/gdbm/gdbm.html下载来安装。如果想在windows下使用GDBM,目前有MinGW和cygwin,不过由于它们都需要一些复杂的支持,而我只是想单纯的使用GDBM,所以我对gdbm-1.8.3做了windows port(windows7 64bits),不过那是以后的话题,和这篇文章关系不大!

  Author       : He YiJun  (storysnail<at>gmail.com QQ:363559089)
  Develop Team : 7fane Team
  Editor       : Yang QiuXi
  Art Designer : He YiJun
  License      : 7fane Team  License 1.0
  Last Update  : 2013-01-09

========DBM数据库简介========

       一般的linux发行版中都会自带了一个符合X/Open技术规范的DBM数据库,这个数据库适合存储相对比较静态的索引化数据。有些人认为DBM根本算不上是个数据库,顶多算是个索引化的文件存储系统,事实也确实如此。DBM原来被称为 DB,最初开发的目的是以新的HASH访问算法来代替旧的hsearch函数和大量的dbm实现,它的第一个发行版出现在1991年,当时还包含了B+树数据访问算法。在1992年,BSD UNIX-4.4发行版中包含了DB1.85版。大家基本上认为这是DB的第一个正式版。在1996年中期,开源软件公司Sleepycat成立 (http://www.sleepycat.com),推出了一个名为”The Berkley Database”的开放源代码的产品并提供商业支持。从这以后,DB得到了广泛的应用,并且出现了很多种分支,例如GDBM。2005年2月15日,甲骨文公司(Oracle Corporation)收购了开源软件公司Sleepycat,并将The Berkley Database数据库添加到了Oracle嵌入式数据库产品线中。

    GDBM是由GNU(http://www.gnu.org)实现的DBM数据库,其特点是简单、小巧、可靠、高性能,并且已经被移植到了windows平台(http://sourceforge.jp/projects/mingw /releases/)。GDBM数据库包含若干条记录,每一个记录由关键字和数据记录(KEY/VALUE)构成。保存在GDBM数据库中的每一个记录都必须有一个独一无二的关键字,数据可以是简单的数据类型,也可以是复杂的数据类型,例如C语言中的结构。技术规范里允许具体实现时把关键字和数据的最大长度限制在1024个字节,但这个限制通常没有什么意义,因为具体实现出来的东西往往比规范更灵活。

========GDBM的数据类型========

    GDBM在头文件gdbm.h中定义了两个新的类型:GDBM_FILE和datum.

typedef struct {int dummy[10];} *GDBM_FILE; 

/* The data and key structure.  This structure is defined for compatibility. */
typedef struct {
    char *dptr;
    int   dsize;
} datum; 

    GDBM_FILE类型指向打开的数据库文件。datum是用typedef语句定义的类型,在使用GDBM数据库时,如果想引用一个数据记录,必须先声明一个datum类型的结构,然后让参数dptr指向数据库里数据记录的起始点,把数据记录的长度放在dsize参数里。

    下面是错误代码,指出了出错类型,通过gdbm_strerr()函数可以得到详细的出错信息。

    0   GDBM_NO_ERROR                 No error
    1    GDBM_MALLOC_ERROR            Malloc error
    2    GDBM_BLOCK_SIZE_ERROR        Block size error
    3    GDBM_FILE_OPEN_ERROR        File open error
    4    GDBM_FILE_WRITE_ERROR        File write error
    5    GDBM_FILE_SEEK_ERROR        File seek error
    6    GDBM_FILE_READ_ERROR        File read error
    7    GDBM_BAD_MAGIC_NUMBER        Bad magic number
    8    GDBM_EMPTY_DATABASE            Empty database
    9    GDBM_CANT_BE_READER            Can't be reader
    10    GDBM_CANT_BE_WRITER            Can't be writer
    11    GDBM_READER_CANT_DELETE        Reader can't delete
    12    GDBM_READER_CANT_STORE        Reader can't store
    13    GDBM_READER_CANT_REORGANIZE    Reader can't reorganize
    14    GDBM_UNKNOWN_UPDATE            Unknown update
    15    GDBM_ITEM_NOT_FOUND            Item not found
    16    GDBM_REORGANIZE_FAILED        Reorganize failed
    17    GDBM_CANNOT_REPLACE            Cannot replace
    18    GDBM_ILLEGAL_DATA            Illegal data
    19    GDBM_OPT_ALREADY_SET        Option already set
    20    GDBM_OPT_ILLEGAL            Illegal option

========GDBM数据库的访问函数========

  1:数据库的创建与打开
    创建和打开数据库使用gdbm_open()函数,它返回一个GDBM_FILE类型的指针,指向打开的数据库文件。如果打开失败,则返回NULL。

GDBM_FILE gdbm_open(char *name,int block_size,int read_write,int mode,void (*fatal_func) ())

    参数简介:

    name:文件名,如果只是文件名,那么文件与程序在同一个目录内。
    block_size:指一次从硬盘写到内存的块的大小,最小为512。通常设置为0,这样GDBM将使用文件系统的默认值。
    read_write:
         GDBM_READER  读模式
         GDBM_WRITER  写模式
         GDBM_WRCREAT 写模式,如果数据库文件不存在则创建数据库文件
         GDBM_NEWDB   写模式,如果数据库文件存在则覆盖原数据库文件
                      通过"|"操作符还可以改变GDBM数据库的写入操作方式,有下面两种可选:
                        GDBM_FAST    在写入数据时,数据内容不会立刻保存到磁盘的数据库文件中,
                                     而是临时保存在内存里,若想将数据写入数据库文件,必须调用
                                     gdbm_sync()函数. 该参数在gdbm-1.8之后成为默认值。
                        GDBM_SYNC    写入的数据时,数据内容会立刻保存到磁盘的数据库文件中.
                      还有一个特别的参数就是下面这个:
                        GDBM_NOLOCK  通常情况下,在某进程已经打开某数据库文件时, 若有其他进程试图
                                     打开该数据库文件的话,就会引发Error,若指定了该标识的话,就可以
                                     同时打开该数据库文件而不会引发Error了.
    mode:
       S_IRWXU           00700 允许文件的属主读、写和执行文件
       S_IRUSR(S_IREAD)  00400 允许文件的属主读文件
       S_IWUSR(S_IWRITE) 00200 允许文件的属主写文件
       S_IXUSR(S_IEXEC)  00100 允许文件的属主执行文件
       S_IRWXG           00070 允许文件所在的分组读、写和执行文件
       S_IRGRP           00040 允许文件所在的分组读文件
       S_IWGRP           00020 允许文件所在的分组写文件
       S_IXGRP           00010 允许文件所在的分组执行文件
       S_IRWXO           00007 允许其它用户读、写和执行文件
       S_IROTH           00004 允许其它用户读文件
       S_IWOTH           00002 允许其它用户写文件
       S_IXOTH           00001 允许其它用户执行文件
    fatal_func:          当出错时执行其指向的函数,通常设置为NULL,那样GDBM可以使用自己默认的函数。

    示例:

  GDBM_FILE dbf;
  dbf = gdbm_open("mydata.db", 0, GDBM_READER, 0, NULL);
  if( dbf == NULL ) {
    printf("Can not open database\n, %s\n", gdbm_strerror(gdbm_errno) );
  } 

  2:数据库的关闭
    关闭已经打开的数据库

void gdbm_close (GDBM_FILE dbf)

    参数简介:

    dbf:指向数据库文件的指针

    示例:

gdbm_close(dbf); 

  3:数据的存储
    GDBM数据库的存储方式是一个关键字对应一条数据记录,关键字类似于数据库中的主键,然而关键字并不一定为数据记录中的字段。GDBM数据库中定义了datum类型,无论是关键字还是数据记录都是以datum类型存储在数据库中的。GDBM不会创建两个一样的关键字;在gdbm_store()函数中选用GDBM_INSERT参数,如果新数据记录的关键字已经存在,那么会返回1,但新的数据记录不会被插入到数据库中.gdbm_store()函数成功插入数据会返回0,失败会返回-1.

int gdbm_store (GDBM_FILE dbf,datum key,datum content,int flag)

    参数简介:

    dbf:      指向数据库文件的指针
    key:      关键字
    content:  记录的数据
    flag:     GDBM_INSERT  插入新记录,如果记录已经存在则报错
              GDBM_REPLACE 插入新记录,如果记录存在则覆盖

    示例:

  char keybuf[256], databuf[256];
  datum key, data; 

  gets(keybuf);
  gets(databuf); 

  key.dptr = keybuf; key.dsize = strlen(keybuf);
  data.dptr = databuf; data.dsize = strlen(databuf); 

  rc = gdbm_store(dbf, key, data, GDBM_INSERT);
  if( rc != 0 ) {
    printf("Can not store record\n, %s\n", gdbm_strerror(gdbm_errno) );
  } 

  4:读取数据库中的数据记录
    根据关键字获取数据库中对应的数据记录.如果在数据库中没有找到关键字,那么返回的datum结构中的dptr将被置空(NULL).如果找到了关键字,返回的datum结构中的dptr会指向一段由malloc申请的内存,在使用完这些数据后需要释放。如果你不喜欢free,可以去使用java版的GDBM。

datum gdbm_fetch (GDBM_FILE dbf,datum key)

    参数简介:

    dbf:指向数据库文件的指针
    key:关键字

    示例:

  char keybuf[256];
  datum key, data; 

  gets(keybuf);
  key.dptr = keybuf; key.dsize = strlen(keybuf); 

  data = gdbm_fetch(dbf, key);
  if( data.dptr == NULL ) {
    puts("Record not found!\n");
  }
  else {
    printf("Record found (%d): %s", data.dsize, data.dptr);
    free(data.dptr);
  } 

  5:数据的删除
    删除一个关键字,注意只是删除了关键字,与该关键字关联的数据记录并没有被删除,如果想删除那个关键字关联的数据记录需要在调用gdbm_delete()之后调用gdbm_reorganize().如果关键字不存在或者文件是使用GDBM_READER参数打开的,那么这个函数会返回-1,成功返回0.

int gdbm_delete (GDBM_FILE dbf,datum key)

    参数简介:

    dbf:指向数据库文件的指针
    key:关键字

    示例:

  char keybuf[256];
  datum key; 

  gets(keybuf);
  key.dptr = keybuf; key.dsize = strlen(keybuf); 

  rc = gdbm_delete(dbf, key);
  if( rc != 0 )
    printf("Record can not delete.\n %s", gdbm_strerror(gdbm_errno)); 

  6:数据的遍历
    使用这两个函数可以依次遍历数据库中的所有数据记录。如果你使用gdbm_open()函数的GDBM_WRITER(或者类似的)打开数据库,那么就需要小心操作,确定在遍历所有数据记录的过程中没有改变任何记录,否则会出现不能完全遍历所有数据记录的情况。如果返回的datum结构中的dptr为NULL,则表示已经遍历的所有的数据记录,已经到达数据库末尾了。

datum gdbm_firstkey (GDBM_FILE dbf)
datum gdbm_nextkey (GDBM_FILE dbf,datum key)

    参数简介:

    dbf:指向数据库文件的指针
    key:关键字

    示例:

  datum key, nextkey;
  int n = 1; 

  puts("Key list:\n");
  key = gdbm_firstkey(dbf);
  while( key.dptr != NULL ) {
    printf("%d: %s", n, key.dptr);
    n++;
    nextkey = gdbm_nextkey(dbf, key);
    free(key.dptr);
    key = nextkey;
  } 

  7:其它GDBM函数
    在GDBM中, 因为删除所腾出空间将会被留作下次存储,所以删除元素后DB文件体积不会减小. 调用该函数后, 将重新生成数据库文件,这样可以避免浪费存储空间,删除大量数据后, 可以使用该方法来节省磁盘空间.

int gdbm_reorganize (GDBM_FILE dbf)

    将元素的变更反映到文件中. 只有在FAST模式时才有效

void gdbm_sync (GDBM_FILE dbf)

    检查数据库中是否有指定的关键字,一般会在读取数据库中的数据记录之前使用该函数。关键字存在,返回1,否则返回0.

int gdbm_exists (GDBM_FILE dbf,datum key)

    根据给定的错误代码返回一段描述错误的字符串信息

char *gdbm_strerror (gdbm_error errno)

    可以使用gdbm_setopt()函数设置GDBM的行为

int gdbm_setopt (GDBM_FILE dbf,int option,int *value,int size)

目前只有两个选项。

         GDBM_CACHESIZE  设定GDBM数据库文件的缓存大小,默认值为100.
         GDBM_FASTMODE   该选项允许你将GDBM数据库切换到fast mode.
                         如果fast mode被开启(value置TRUE), GDBM将
                         不会立刻将数据保存到磁盘的数据库文件中,
                         直到你调用gdbm_sync()函数才会将数据完全
                         保存到数据库文件里.

========一个应用GDBM的例子========

    下面将使用一个具体的例子gdbm-test.c来说明GDBM的使用

#include<gdbm.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<string.h>
#include<stdio.h>
#include<ctype.h> 

#define DB_FILE_BLOCK "book_data"
#define ISBN_MAX 13
#define AUTHOR_MAX 50
#define TITLE_MAX 50
#define FILED_MAX 50               /*最宽的数据域 */ 

/*定义图书结构体 */ 
typedef struct {        
    char isbn[ISBN_MAX + 1];
    char author[AUTHOR_MAX + 1];
    char title[TITLE_MAX + 1];
    int  numb;
} book_entry; 

char *str_con(char *input, int len)
{
    int count = 0;
    do {
        input[count] = tolower(input[count]);
        count++;
    } while (count <= len);
    return input;
}
int main()
{
    book_entry newbook; /*创建新的图书记录,并赋值 */
    datum key, data;    /*datum结构体有两个成员:dptr指向存储的数据,dsize记录数据的大小 */
    GDBM_FILE dbm_ptr;
    char isbnarr[ISBN_MAX + 1] = { 0 };
    char *isbn = isbnarr;
    book_entry vbook, sbook;/*vbook存储数据库中的原始记录,sbook是转换成小写以后的*/
    char keyword[FILED_MAX];
    memset(&newbook, '\0', sizeof(newbook));
    strncpy(newbook.isbn, "9787302184942", ISBN_MAX);
    strncpy(newbook.author, "Microsoft Research Asia", AUTHOR_MAX);
    strncpy(newbook.title, "Microsoft's Dream Works", TITLE_MAX);
    newbook.numb = 735;
    key.dptr = (char *)newbook.isbn;    /*用ISBN作key */
    key.dsize = ISBN_MAX;
    data.dptr = (char *)&newbook;       /*用整条数据记录作value */
    data.dsize = sizeof(newbook);
    /*打开数据库(跟打开文件很相似),返回数据库句柄 */
    dbm_ptr = gdbm_open(DB_FILE_BLOCK,  /*文件名 */
                0,                      /*文件大小,设为0时GDBM将使用文件系统的统计块大小 */
                GDBM_WRCREAT,           /*读写模式。WRCREAT读写,数据库文件不存在时创建;READER读;WRITER写 */
                S_IRUSR | S_IWUSR,      /*权限标志位 */
                NULL);                  /*出错时的空参数回调函数 */
    /*把记录存入数据库 */
    gdbm_store(dbm_ptr,                 /*数据库句柄 */
           key,                         /*key值 */
           data,                        /*value值 */
           GDBM_REPLACE);               /*GDBM_INSERT则插入重复记录会出错;GDBM_REPLACE则会覆盖存在的相同记录 */
    /*得到用户的输入,这里只是一个示例,并没考虑缓冲区溢出等问题*/
    puts("请输入你要查询图书的ISBN号:");
    scanf("%s",isbn);
    key.dptr = (char *)isbn;
    key.dsize = ISBN_MAX;
    /*读取数据库中的数据记录*/
    data = gdbm_fetch(dbm_ptr, key);   
    if (data.dsize == 0)
        printf("查无结果\n");
    else {
        memset(&newbook, 0, sizeof(newbook));
        memcpy(&newbook, data.dptr, data.dsize);    /*将从数据库读到的记录赋给book_entry结构体 */
        printf("%s\t%s\t%s\t%d\n", newbook.isbn, newbook.author,newbook.title, newbook.numb);
    }
    /*得到用户的输入*/
    printf("请输入一个关键字开始模糊查询:");
    scanf("%s",keyword);
    for (key = gdbm_firstkey(dbm_ptr); key.dptr;key = gdbm_nextkey(dbm_ptr, key)) {
        data = gdbm_fetch(dbm_ptr, key);
        memcpy(&sbook, data.dptr, data.dsize);
        memcpy(&vbook, data.dptr, data.dsize);
        strcpy(keyword, str_con(keyword, FILED_MAX));
        strcpy(sbook.isbn, str_con(sbook.isbn, ISBN_MAX));
        strcpy(sbook.title, str_con(sbook.title, TITLE_MAX));
        strcpy(sbook.author, str_con(sbook.author, AUTHOR_MAX));
        if ((strstr(sbook.isbn, keyword) || strstr(sbook.title, keyword) || strstr(sbook.author, keyword))) {
            printf("%s\t%s\t%s\t%d\n", vbook.isbn, vbook.author,vbook.title, vbook.numb);
        } else {
            printf("查无记录\n");
        }
    }    
    /*关闭数据库 */
    gdbm_close(dbm_ptr);
    exit(0);
} 

    在windows下用codeblocks的MinGW编译,需要在
    Settings->Compiler and debugger settings->Global compiler settings->Linker settings中的
    Other linker options中添加-lgdbm参数。
    linux编译gdbm-test.c用下面的命令即可:

gcc -o gdbm-test  gdbm-test.c -lgdbm 

//有些版本还需要链接一个gdbm_compat库
gcc -o gdbm-test  gdbm-test.c -lgdbm  -lgdbm_compat 
 
 
 
 

            7fane Team 协议 1.0  中文版

    当您阅读、理解并愿意遵守以下条款时,您就拥有了获取、使用、复制、分发或通过通信
网络传播7fane Team作品的权利。

1. 7fane Team的作品可以在非商业用途下免费使用。

2. 如果软件提供了源代码,那么你可以更改源代码或软件接口以适应你的应用。

3. 在未获得7fane Team的授权之前,你不可以在商业用途下使用7fane Team的作品,
   也不可以将7fane Team的作品用于营利为目的的活动。关于获得许可,请发送Email
   到storysnail@gmail.com以获取更多信息。

4. 你不得租赁,再许可,出售,转让,抵押7fane Team的作品和服务。

5. 你不得删除或修改7fane Team作品的版权信息和相关的链接,例如网址信息或“关于窗口”
   中的所有信息,除非您已经获得7fane Team的书面授权。

6. 你不可以通过修改7fane Team的作品来获得衍生作品,更不可以重新分配这些衍生作品。

7. 如果您不能遵守本协议,您的许可将被终止,您必须停止使用并删除7fane Team作品及其
   副本,并且不可以再继续获取、使用、复制、分发或通过通信网络传播7fane Team作品。

8. 7fane Team拥有并保留修改本协议的权利和在本协议修改后不另行通知的权利。修改后
   的新协议将适用于新的许可用户。

9. 7fane Team作品是作为不提供任何明确的或隐含的赔偿或担保的形式提供的。

10.7fane Team对于使用其作品而生成的任何信息不承担任何责任,也不会对传播或使用
   这些信息承担责任。

11. 用户出于自愿而使用本7fane Team作品,您必须了解使用的风险,我们不承诺对用户提供
   任何形式的技术支持、使用担保,所以你必须承担全部风险。
关于 "7fane Team作品" 的定义:
    "7fane Team作品" 包括文本、图像、音频视频、软件等由7fane Team创作的一切。

    版权所有 (c)2001-2012,7fane Team 保留所有权利。


<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值