我在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; }