iOS标准库中常用数据结构和算法之KV数据库

上一篇: 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-value值同步到磁盘中去
头文件: #include<db.h>
平台: BSD Unix
描述:
针对ndbm数据库,系统并没有直接提供将内存数据同步到磁盘的API。除了提供ndbm外,系统提供了一个更加通用的文件数据库接口,这些接口定义在db.h文件中。从头文件的声明中我们可以看到系统提供的db的类型以及关于数据库句柄的详细定义:

 //三种数据库类型:B树、HASH表、记录
typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;

//通用的数据库句柄定义。
typedef struct __db {
    DBTYPE type;            /* 类型 */
    int (*close)(struct __db *);  //关闭库函数
    int (*del)(const struct __db *, const DBT *, unsigned int);  //删除元素函数
    int (*get)(const struct __db *, const DBT *, DBT *, unsigned int);  //获取元素函数
    int (*put)(const struct __db *, DBT *, const DBT *, unsigned int); //设置元素函数
    int (*seq)(const struct __db *, DBT *, DBT *, unsigned int); //序列号生成函数
    int (*sync)(const struct __db *, unsigned int);  //同步函数
    void *internal;         /* 内部结构 */
    int (*fd)(const struct __db *);   //得到文件描述符函数
} DB;

而我们使用的key-value库内部其实是一种DB_HASH类型的数据库文件。同时DBM类型其实也是一种DB类型。因此当我们需要进行磁盘同步时只需要将DBM类型的句柄转化为DB类型的句柄,然后调用其中sync函数就可以实现磁盘文件的同步了。这样我们就可以在需要将内存数据保存到磁盘是直接调用同步函数而不需要通过关闭文件来达到磁盘存储的目的。

示例代码:

  DBM *dbm = XXX;  //假设DBM是在其他地方打开的数据库文件句柄.
  DB *db = (DB*)dbm;  //转化为DB类型指针。
  db->sync(db, 0);  //这里调用这个函数就可以实现内存数据到磁盘的同步处理了。

遍历

功能:系统提供了两个遍历的函数,分别是获取整个数据库中最开始的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而有些系统则没有这个限制。

下一篇:iOS标准库中常用数据结构和算法之位串


欢迎大家访问欧阳大哥2013的github地址简书地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容