作者: 遊手好閒的石頭成 E-Mail: shirock@mail.educities.edu.tw ------------- GDBM 使用範例 以下我提供了三個完整的程式範例,示範 GDBM 的使用。 在編譯,必須連結 gdbm 這個 library ,如下: $ gcc -O db_add.c -o db_add -lgdbm ------------------------------------------------ /* db_add.c: storing written by rock , 1999.11.29 */ #include #include #include #define datum_set(um, buf) { um.dptr = buf; um.dsize = strlen(buf); } int main(int argc, char *args[]) { char keyb[256], datab[256], *dbname; GDBM_FILE dbf; datum key, data; if( argc < 2) { puts("Usage: db_add \n"); return 1; } dbname = args[1]; if( !(dbf = gdbm_open(dbname, 0, GDBM_WRCREAT, 0644, NULL)) ) { printf("%s\n", gdbm_strerror(gdbm_errno)); return 1; } puts("Input key: "); gets(keyb); puts("Input data: "); gets(datab); datum_set(key, keyb); datum_set(data, datab); if( gdbm_store(dbf, key, data, GDBM_INSERT) ) { printf("%s\nRecord may be exist.\n", gdbm_strerror(gdbm_errno)); gdbm_close(dbf); return 1; } puts("Storing record successed.\n"); gdbm_close(dbf); return 0; } ------------------------------------------------ /* db_ls.c: retrieval written by rock , 1999.11.29 */ #include #include #include int main(int argc, char *args[]) { GDBM_FILE dbf; datum key, next, data; int n = 1; char *dbname; if( argc < 2) { puts("Usage: db_ls \n"); return 1; } dbname = args[1]; dbf = gdbm_open(dbname, 0, GDBM_READER, 0, NULL); if(!dbf) { printf("%s\n", gdbm_strerror(gdbm_errno)); return 1; } key = gdbm_firstkey(dbf); while( key.dptr ) { data = gdbm_fetch(dbf, key); printf("(%d) %s:\t%s\n", n++, key.dptr, data.dptr); next = gdbm_nextkey(dbf, key); free(key.dptr); key = next; } gdbm_close(dbf); return 0; } ------------------------------------------------ /* db_rm.c: deletion written by rock , 1999.11.29 */ #include #include #include int main(int argc, char *args[]) { GDBM_FILE dbf; char keyb[256], *dbname; datum key; if( argc < 2) { puts("Usage: db_rm \n"); return 1; } dbname = args[1]; dbf = gdbm_open(dbname, 0, GDBM_WRITER, 0, NULL); if( !dbf ) { printf("%s\n", gdbm_strerror(gdbm_errno)); return 1; } puts("Input key: "); gets(keyb); key.dptr = keyb; key.dsize = strlen(keyb); if(gdbm_delete(dbf, key)) { printf("%s\n", gdbm_strerror(gdbm_errno)); gdbm_close(dbf); return 1; } puts("Removing record successed\n"); gdbm_close(dbf); return 0; } ------------------------------------------------ 使用結果示範如下: ------------------------------------------------ $ db_add Usage: db_add $ db_add email_list.db Input key: rock Input data: shirock@residence.educities.edu.tw, 847-1023 Storing record successed. $ db_ls email_list.db (1) rock: shirock@residence.educities.edu.tw, 847-1023 $ db_rm email_list.db Input key: abc Item not found $ db_rm email_list.db Input key: rock Removing record successed ------------------------------------------------ 還有一個使用上的問題是,當你的程式可能運作在多人同時操作的環境時, GDBM 在無法 開啟時,不擱置立即返回的特色,可能會造成程式設計上的困擾。一般你需要再加上一個 防衛措施,故且稱為衛兵,在開啟資料庫前,先通過這個衛兵的檢查,如果你可以立即取 得資料庫的使用權,再呼叫 gdbm_open() 開啟資料庫。 若無法立即取得,則由衛兵將此 工作擱置下來。 這個衛兵需要具有共用、互斥的防衛機制,一般會透過 semaphore (信號) 或是 locking (檔案鎖定) 來實作。 semaphore (信號) 的使用,請參考本人另一篇文章「如何以 semaphore 進行資源的共用 互斥鎖定」。 檔案鎖定的方式,則是另外建立一個檔案,就稱為衛兵好了,當欲成為資料庫的 reader 時,先開啟這個衛兵,然後以 SHLOCK (共享鎖定) 的方式鎖上衛兵,若目前無法上鎖, 系統就會將工作自動擱置下來。若欲成為資料庫的 writer ,則對此衛兵以 EXLOCK (互 斥鎖定) 的方式上鎖。 在 BSD 上提供的檔案鎖定函數叫 flock() ,在 SYSV 上提供的叫 lockf() ,但我強烈 建議使用 POSIX 所規範的 fcntl() 上鎖方式,此方式具有普遍性及一致性。