上一篇: iOS标准库中常用数据结构和算法之哈希表
KV数据库
对于结构化数据的存储一般我们使用关系型数据库,而对于基于key-value类型的数据存储则不适合用关系型数据库。因此iOS系统也内置了一套基于key-value存储的文件数据库:ndbm。
功能:
一套基于key-value形式存储的数据库。
头文件: #include <ndbm.h>
平台: BSD Unix
1.创建、打开、关闭
功能: 数据库文件的创建、打开、关闭。
函数签名
//数据库文件的创建或者打开
DBM * dbm_open(const char *file, int open_flags, mode_t file_mode);
//数据库文件的关闭
void dbm_close(DBM *db);
参数:
file:[in] 指定数据库的文件名,系统在打开和创建时会在内部自动添加.db的后缀名称,因此我们不需要指定后缀扩展名部分。
open_flags: [in] 文件的打开属性,一般传递O_RDWR | O_CREAT 表明读写以及不存在时创建。
file_mode:[in] 文件的访问权限模式,一般设置为0660。
db:[in] 用于执行数据库关闭的句柄,这个句柄是由数据库文件打开所返回的。
return:[out] 数据库创建成功时返回的数据库句柄指针,数据库句柄指针是一个DBM类型的数据,这个类型对我们透明,也不需要我们去关心, 当打开失败时返回NULL。
2.添加
功能:将某个key-value键值对添加到数据库中。系统并没有对key-value的内容做限制,但是在进行添加处理时必须要转化为如下定义的结构体:
typedef struct {
void *dptr; //内存数据的地址
size_t dsize; //内存数据的尺寸。
} datum;
函数签名:
int dbm_store(DBM *db, datum key, datum content, int store_mode);
参数:
db: [in] 数据库句柄。
key:[in] 要插入的key部分的内容。
content:[in] 要插入的value部分的内容。
store_mode:[in] 插入的模式,可以指定为DBM_INSERT或DBM_REPLACE。当指定为DBM_INSERT时表明是插入,如果此时数据库中存在对应的key时则此次操作会返回失败;当指定为DBM_REPLACE时则当不存在时会执行添加处理,而当对应的key存在时就会执行替换处理。
return:[out] 当添加成功时返回0,当返回1时表明插入一个已经存在的key,当返回-1时表明插入失败。
删除
功能: 从数据库中删除某个key-value键值对。
函数签名:
int dbm_delete(DBM *db, datum key);
参数:
db: [in] 数据库句柄。
key:[in] 要删除的键。
return:[out] 如果返回0则删除成功,返回1则表明不存在指定的key,返回-1则是其他错误。
查询
功能: 根据指定的key从数据库中查找对应的value值。
函数签名:
datum dbm_fetch(DBM *db, datum key);
参数
db:[in] 数据库句柄。
key:[in] 查找指定的key
return:[out] 系统返回一个结构体datum, 存储返回的value值。如果key没有对应的value 值, 那么返回的datum中的dptr的值将是NULL。我们不需要对返回的值进行内存释放,也不能对返回的值的内容进行修改。
遍历
功能:系统提供了两个遍历的函数,分别是获取整个数据库中最开始的key值,以及获取下一个有效的key值的函数.
函数签名:
//获取第一个存储的key值。
datum dbm_firstkey(DBM *db);
//获取下一个存储的key值。
datum dbm_nextkey(DBM *db);
参数:
db:[in]数据库句柄
return: 返回对应的key值,如果没有key值那么返回的结构体中的dptr的值将是NULL。
描述:
你可以通过这两个函数来依次遍历整个数据库中的key值,然后再结合dbm_fetch来获取对应的value。需要注意的是如果某次遍历期间中执行了插入或者删除操作则应该要重新进行遍历,否则得到的结果未可知。
示例代码:
//遍历函数
void traversendbm(DBM *dbm)
{
printf("start:-------------\n");
datum key = dbm_firstkey(dbm);
while (key.dptr != NULL)
{
datum val = dbm_fetch(dbm, key);
if (val.dptr != NULL)
{
printf("key=%s, val=%s\n",key.dptr, val.dptr);
}
key = dbm_nextkey(dbm);
}
printf("end:-------------\n");
}
void main()
{
DBM *dbm = dbm_open("/Users/apple/testdb", O_RDWR | O_CREAT, 0660);
datum key1,val1,key2,val2;
key1.dptr = "aa";
key1.dsize = 3;
key2.dptr = "bb";
key2.dsize = 3;
val1.dptr = "vvv1";
val1.dsize = 5;
val2.dptr = "vvv2";
val2.dsize = 5;
//添加
if (dbm_store(dbm, key1, val1, DBM_INSERT) < 0)
{
printf ("insert error:%d\n", dbm_error(dbm));
}
if (dbm_store(dbm, key2, val2, DBM_INSERT) < 0)
{
printf ("insert error:%d\n", dbm_error(dbm));
}
traversendbm(dbm);
//替换
val1.dptr = "vvv3";
val1.dsize = 5;
if (dbm_store(dbm, key1, val1, DBM_REPLACE) < 0)
{
printf ("insert error:%d\n", dbm_error(dbm));
}
traversendbm(dbm);
//删除
int ret1 = dbm_delete(dbm, key1);
trandbm(dbm);
//关闭
dbm_close(dbm);
}
在iOS系统的内部实现中所有的添加或者删除操作如果不执行dbm_close的话那么都不会实际保存到磁盘文件中。因此如果你在iOS系统中使用这套API则要记得在合适的时候执行数据库关闭处理。
有一些Unix系统中对key-value的长度限制为1024而有些系统则没有这个限制。
网友评论