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() 。
阅读(16057) | 评论(1) | 转发(0) |