Chinaunix首页 | 论坛 | 博客
  • 博客访问: 946722
  • 博文数量: 58
  • 博客积分: 10192
  • 博客等级: 上将
  • 技术积分: 1845
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-22 21:24
文章分类

全部博文(58)

文章存档

2011年(11)

2010年(12)

2009年(20)

2008年(15)

分类: C/C++

2008-04-29 11:27:02

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() 。
阅读(3531) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~