我在ubuntu是需要先安装GDBM的。
总结一下GDBM的特点:
- 按key-value存储数据,value是可变长的。它只对key进行索引,只能按key进行查询。
- 高效的查询,低效的插入,适合于存储比较静态的数据。
- GDBM可以很容易地编译进一个可发布的二进制文件中,不需要独立地安装数据库服务器。
- 不支持SQL,不支持表之间创建关系,更不用说存储过程、触发器什么的了。
操作GDBM就跟操作文件很相似,下面的代码用于创建一个数据库,并存入一条记录。
#include<gdbm.h> #include<stdlib.h> #include<stdio.h> #include<sys/stat.h> #include<string.h> #define ISBN_MAX 13 #define AUTHOR_MAX 50 #define TITLE_MAX 50 #define DB_FILE_BLOCK "book_data" typedef struct { /*定义图书结构体 */ char isbn[ISBN_MAX + 1]; char author[AUTHOR_MAX + 1]; char title[TITLE_MAX + 1]; int numb; } book_entry; int main() { book_entry newbook; /*创建新的图书记录,并赋值 */ 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; datum key, data; /*datum结构体有两个成员:dptr指向存储的数据,dsize记录数据的大小 */ key.dptr = (char *)newbook.isbn; /*用ISBN作key */ key.dsize = ISBN_MAX; data.dptr = (char *)&newbook; /*用整条数据记录作value */ data.dsize = sizeof(newbook); GDBM_FILE dbm_ptr; /*打开数据库(跟打开文件很相似),返回数据库句柄 */ 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则只是覆盖原先存在的相同记录 */ ); char isbnarr[ISBN_MAX + 1] = { 0 }; char *isbn = isbnarr; puts("请输入你要查询图书的ISBN号:"); scanf("%s",isbn); key.dptr = (char *)isbn; key.dsize = ISBN_MAX; /*数据库查询 */ data = gdbm_fetch(dbm_ptr, key); /*参建:数据库句柄的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); } /*关闭数据库 */ gdbm_close(dbm_ptr); }
由于GDBM只支持按key查询,如果我们想持按data中的某个字段查询,就必须自己遍历数据库,逐一地和记录(这是个struct)的特定成员进行对比。
我们通过两个函数来遍历数据库:
gdbm_firstkey(dbm_ptr) 获取数据库第一条记录的key值
gdbm_nextkey(dbm_ptr, key) 获取下一条记录的key值
要想实现模糊查询也只能借助于strstr()函数,它用于判断子串是否在主串中出现过。当然调用strstr之前,你通常还需要统计转换为大写或者小写,tolower和touper可以对单个字符进行大小写转换。
下面的代码就是遍历数据库,进行模糊查询。
#include<string.h> #include<stdlib.h> #include<sys/stat.h> #include<gdbm.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() { GDBM_FILE dbm_ptr; datum key, data; book_entry vbook, sbook;/*vbook存储数据库中的原始记录,sbook是转换成小写以后的*/ char keyword[FILED_MAX]; printf("请输入一个关键字开始模糊查询:"); scanf("%s",keyword); dbm_ptr = gdbm_open(DB_FILE_BLOCK, 0, GDBM_READER, 0, NULL); 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); } return 0; }