GDBM/NDBM使用介紹
GDBM - GNU database manager,一套簡單的資料庫管理函數。
gdbm 的常見版本是 1.73 ,在大部份的 FreeBSD, Linux 系統中皆已提供,若未提供,
則可利用搜尋引擎尋找 gdbm-1.7.3.tar.gz 或 gdbm-1.8.0.tar.gz 並下載,利用
configure 指令即可輕鬆安裝。
在安裝時,可以選擇是否一併安裝 dbm 及 ndbm 的相容介面。
dbm 是 UNIX 上一套古老的常見資料庫處理介面,而 ndbm 則是改良 dbm 缺失而設計的,
兩者的介面差異頗大。
gdbm 則是根據 ndbm 的介面設計的,兩者間非常相似, ndbm 的函數名稱皆以 dbm_ 開頭,
而 gdbm 為了加以區別,則以 gdbm_ 開頭,除此之外,皆可對應。
gdbm 所提供的資料庫管理介面,與 ndbm 非常相似,因此 gdbm 的說明,也可以適用於
ndbm 上。
可用兩種方式判斷有無安裝 gdbm :
1.查詢有無 gdbm 的 manpage
$ man gdbm
2.查詢有無 gdbm 的 library
$ ls /usr/lib/libgdbm*
gdbm 提供一套管理 key/data 類型的資料庫的函數,其特徵是資料庫中,每筆記錄都有
一個唯一的鍵值。
這種 key/data 格式的資料檔案其實很常見,例如:
--------------------------------------------
rock: 983-1231, rock@isu.edu.tw
xyz: 931-4321, xyz@touc.edu.tw
--------------------------------------------
一個鍵值,一個記錄內容。
在使用 gdbm 前,通常我們會用循序檔來存放這類的資料,一筆一行或一區塊,一
筆一筆的存下來,這樣的好處是:
1.修改方便
可以用一般的文字編輯工具增修資料,不用另行設計。
2.節省空間
有多少資料就用多少空間,不像用 struct 的隨機檔,不論資料量多少,所有
記錄都佔同樣的空間。
但其缺點有:
1.管理不便
當記錄數達數百、甚至數萬筆時,繼續用這種方式管理,可是件令人痛苦的事。
2.使用負擔大
資料搜尋費時,所有資料都必須從頭開始找,在增修資料時也很費功夫,當資料
量大、使用率高時,會對系統造成負擔。
而 gdbm 則是針對此缺點提出的一個解決方案,其利用 hash 表存放鍵值,大幅節省
搜尋時間,同時仍允許記錄採用浮動長度,在時間及空間兩者中取得平衡。
其 hash 表是用可擴充式 hash 表演算法,會視需要自動擴充 hash 表,不需擔心
hash 表的大小。
gdbm 將資料庫管理動作分成三個:
1.storing 儲存
2.retrieval 擷取
3.deletion 刪除
加上開啟資料庫及走訪(visiting)的動作,提供七個主要的函數。
再加上一個存放上述函數呼叫錯誤狀態值的變數 gdbm_errno 。
其 prototype 如下:
=================================================
#include
typedef struct {
char *dptr;
int dsize;
} datum;
extern gdbm_error gdbm_errno;
GDBM_FILE gdbm_open (name, block_size, read_write, mode, fatal_func);
char * name;
int block_size, read_write, mode;
void (*fatal_func) ();
void gdbm_close (dbf);
GDBM_FILE dbf;
int gdbm_store (dbf, key, content, flag);
GDBM_FILE dbf;
datum key, content;
int flag;
datum gdbm_fetch (dbf, key);
GDBM_FILE dbf;
datum key;
int gdbm_delete (dbf, key);
GDBM_FILE dbf;
datum key;
datum gdbm_firstkey (dbf);
GDBM_FILE dbf;
datum gdbm_nextkey (dbf, key);
GDBM_FILE dbf;
datum key;
=================================================
datum 是用來表示記錄鍵值及記錄內容的 structure 。
1.gdbm_open()
開啟資料庫。
gdbm 將開啟者分成 reader 及 writer ,在同一時間內可以有多個 reader ,
但一次只能有一個 writer 。 當指定的資料庫有 reader 在使用時,其他人就無
法成為 writer ,當有 writer 在使用時,其他人就無法成為 reader 或 writer。
GDBM_FILE 是傳回給開啟者的 handle 值。
name 是資料庫的檔案名稱,此檔案是完整的, gdbm 不會添加其他字眼上去。
而 gdbm 也就只會建立這一個資料庫檔案,不會另外再建索引檔或關連檔。
block_size 在建立資料庫時指定,指示 gdbm 以多大的記憶體區塊來讀寫磁碟資
料,此值最小是 512 (bytes) ,但不妨指定 0 ,由 gdbm 自行根據檔案系統的狀
態決定。
read_write 在指示開啟者的開啟型式,可指定的有四:
GDBM_READER 成為 reader
GDBM_WRITER 成為 writer
GDBM_WRCREAT 成為 writer ,若資料庫不存在則建立之
GDBM_NEWDB 成為 writer ,並建立新的資料庫,不論是否存在舊資料庫
若欲成為 writer ,則可以再附帶一個設定值 GDBM_FAST ,指示 gdbm 在寫入資
料時,不要馬上進行與磁碟內容的同步化動作。
此行為在 gdbm 1.8 後,為預設動作。
mode 在指示建立資料庫時,檔案的屬性,其意義同 chmod() 。
一般設為 0644 (rw-r--r--),若沒有建立資料庫的動作,則指定 0 即可。
Fatal_func 為函數指標,當開啟資料庫,發現一個錯誤時,就呼叫該函數,
一般皆設為 NULL ,由 gdbm 自行以預設動作處理。
當 gdbm 無法成為 reader 或 writer 時,會立即返回,而不會自動擱置,
此時 gdbm_open() 傳回 NULL ,可由 gdbm_errno 得知錯誤狀態碼。
範例:
---------------------------------------
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.gdbm_close()
關閉資料庫,不會有錯誤傳回。
範例:
---------------------------------------
gdbm_close(dbf);
---------------------------------------
3.gdbm_store()
儲存記錄。
將記錄鍵值及記錄內容存入資料庫中,存入動作分為增加及替代,在 flag 中指定,
其值有二:
GDBM_INSERT 增加一筆新記錄,若鍵值已存在,則儲存動作失敗。
GDBM_REPLACE 替代記錄內容。
其傳回值有三:
-1 無法儲存。
0 儲存成功。
1 當使用 GDBM_INSERT 時,鍵值已存在,無法儲存。
範例:
---------------------------------------
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) );
}
---------------------------------------
注意,這裡示範的是資料鍵值及內容都是一般文字,如果鍵值及內容中,包
含 '\0' 時,就不能用 strlen() 去計算 size 了。
4.gdbm_fetch()
根據指定鍵值擷取記錄。
傳回記錄的內容,要注意的是,記錄內容的空間是由 gdbm 以 malloc() 配置的,
但 gdbm 不會自動釋放,故當你不再使用該資料時,記得將其釋放。
若記錄內容指向 NULL ,表無此記錄。
範例:
---------------------------------------
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);
}
---------------------------------------
若你只是單純地想查詢鍵值是否已存在於資料庫,而不想擷取資料內容時,可以使
用 gdbm_exists(dbf, key) ,其傳回非零值(true)時,表示鍵值存在。
5.gdbm_delete()
根據指定鍵值移除記錄。
傳回 0 表示成功刪除, -1 表示刪除失敗。
範例:
---------------------------------------
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_firstkey() / gdbm_nextkey()
走訪資料庫。
根據 hash 表走訪資料庫,由於其並非根據資料存入順序或鍵值的排序走訪,因此
走訪結果並無次序,但可以保證的是,每筆記錄都會被走訪一次,不會遺漏。
key.dptr 是由 gdbm 以 malloc() 配置的,但 gdbm 不會自動釋放,故當你走訪完
畢時,記得將其釋放。
當 key.dptr 指向 NULL 時,表示走訪完畢。
注意,當你在走訪資料庫時,不要增加或刪除任何記錄,因為這將改變 hash 表的
內容,造成其走訪時的遺漏。
範例:
---------------------------------------
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_reorganize()
重整資料庫。
這個函數使用時,請再三斟酌,不要常使用。
隨著資料庫的增刪,時間一久,資料庫中,就會留下許多未被使用的空隙,此時可
呼叫 gdbm_reorganize(dbf) 進行資料庫的重整,去除那些空隙,適度縮減資料庫
檔案的大小。
除非呼叫 gdbm_reorganize() ,否則 gdbm 不會縮減資料庫檔案的長度,但是 gdbm
也不是一直往後增加資料,當舊有資料被刪除時, gdbm 會儘然重複使用那些空下來
的空間。
附註:
1.參考文件 GDBM(3), gdbm.h
詳細說明請參閱此 manpage 。
$ man gdbm
2.在本文中,一共提到了十個 gdbm 函數及一個 gdbm 變數:
gdbm_open()
gdbm_close()
gdbm_store()
gdbm_fetch()
gdbm_delete()
gdbm_firstkey()
gdbm_nextkey()
gdbm_exists()
gdbm_reorganize()
gdbm_strerror()
gdbm_errno
reader 無法使用 gdbm_store(), gdbm_delete() 及 gdbm_reorganize() 。
阅读(3688) | 评论(0) | 转发(1) |