iOS標(biāo)準(zhǔn)庫中常用數(shù)據(jù)結(jié)構(gòu)和算法之KV數(shù)據(jù)庫

上一篇: iOS標(biāo)準(zhǔn)庫中常用數(shù)據(jù)結(jié)構(gòu)和算法之哈希表

??KV數(shù)據(jù)庫

對于結(jié)構(gòu)化數(shù)據(jù)的存儲一般我們使用關(guān)系型數(shù)據(jù)庫编检,而對于基于key-value類型的數(shù)據(jù)存儲則不適合用關(guān)系型數(shù)據(jù)庫么介。因此iOS系統(tǒng)也內(nèi)置了一套基于key-value存儲的文件數(shù)據(jù)庫:ndbm古胆。

功能:
一套基于key-value形式存儲的數(shù)據(jù)庫驮捍。
頭文件: #include <ndbm.h>
平臺: BSD Unix

1.創(chuàng)建、打開计济、關(guān)閉

功能: 數(shù)據(jù)庫文件的創(chuàng)建饭入、打開、關(guān)閉。
函數(shù)簽名

//數(shù)據(jù)庫文件的創(chuàng)建或者打開
DBM * dbm_open(const char *file, int open_flags, mode_t file_mode);
//數(shù)據(jù)庫文件的關(guān)閉
void  dbm_close(DBM *db);

參數(shù):
file:[in] 指定數(shù)據(jù)庫的文件名层宫,系統(tǒng)在打開和創(chuàng)建時會在內(nèi)部自動添加.db的后綴名稱杨伙,因此我們不需要指定后綴擴展名部分。
open_flags: [in] 文件的打開屬性萌腿,一般傳遞O_RDWR | O_CREAT 表明讀寫以及不存在時創(chuàng)建限匣。
file_mode:[in] 文件的訪問權(quán)限模式,一般設(shè)置為0660毁菱。
db:[in] 用于執(zhí)行數(shù)據(jù)庫關(guān)閉的句柄米死,這個句柄是由數(shù)據(jù)庫文件打開所返回的。
return:[out] 數(shù)據(jù)庫創(chuàng)建成功時返回的數(shù)據(jù)庫句柄指針贮庞,數(shù)據(jù)庫句柄指針是一個DBM類型的數(shù)據(jù)峦筒,這個類型對我們透明,也不需要我們?nèi)リP(guān)心, 當(dāng)打開失敗時返回NULL窗慎。

2.添加

功能:將某個key-value鍵值對添加到數(shù)據(jù)庫中物喷。系統(tǒng)并沒有對key-value的內(nèi)容做限制,但是在進行添加處理時必須要轉(zhuǎn)化為如下定義的結(jié)構(gòu)體:

typedef struct {
    void *dptr;    //內(nèi)存數(shù)據(jù)的地址
    size_t dsize;  //內(nèi)存數(shù)據(jù)的尺寸遮斥。
} datum;

函數(shù)簽名

int dbm_store(DBM *db, datum key, datum content, int store_mode);

參數(shù)
db: [in] 數(shù)據(jù)庫句柄峦失。
key:[in] 要插入的key部分的內(nèi)容。
content:[in] 要插入的value部分的內(nèi)容术吗。
store_mode:[in] 插入的模式尉辑,可以指定為DBM_INSERT或DBM_REPLACE。當(dāng)指定為DBM_INSERT時表明是插入藐翎,如果此時數(shù)據(jù)庫中存在對應(yīng)的key時則此次操作會返回失敳牡拧;當(dāng)指定為DBM_REPLACE時則當(dāng)不存在時會執(zhí)行添加處理吝镣,而當(dāng)對應(yīng)的key存在時就會執(zhí)行替換處理堤器。
return:[out] 當(dāng)添加成功時返回0,當(dāng)返回1時表明插入一個已經(jīng)存在的key末贾,當(dāng)返回-1時表明插入失敗闸溃。

刪除

功能: 從數(shù)據(jù)庫中刪除某個key-value鍵值對。
函數(shù)簽名:


 int dbm_delete(DBM *db, datum key);

參數(shù):
db: [in] 數(shù)據(jù)庫句柄拱撵。
key:[in] 要刪除的鍵辉川。
return:[out] 如果返回0則刪除成功,返回1則表明不存在指定的key拴测,返回-1則是其他錯誤乓旗。

查詢

功能: 根據(jù)指定的key從數(shù)據(jù)庫中查找對應(yīng)的value值。
函數(shù)簽名:

 datum dbm_fetch(DBM *db, datum key);

參數(shù)
db:[in] 數(shù)據(jù)庫句柄集索。
key:[in] 查找指定的key
return:[out] 系統(tǒng)返回一個結(jié)構(gòu)體datum, 存儲返回的value值屿愚。如果key沒有對應(yīng)的value 值, 那么返回的datum中的dptr的值將是NULL汇跨。我們不需要對返回的值進行內(nèi)存釋放,也不能對返回的值的內(nèi)容進行修改妆距。

磁盤同步

功能: 將內(nèi)存中保存的key-value值同步到磁盤中去
頭文件: #include<db.h>
平臺: BSD Unix
描述:
針對ndbm數(shù)據(jù)庫穷遂,系統(tǒng)并沒有直接提供將內(nèi)存數(shù)據(jù)同步到磁盤的API。除了提供ndbm外娱据,系統(tǒng)提供了一個更加通用的文件數(shù)據(jù)庫接口蚪黑,這些接口定義在db.h文件中。從頭文件的聲明中我們可以看到系統(tǒng)提供的db的類型以及關(guān)于數(shù)據(jù)庫句柄的詳細(xì)定義:

 //三種數(shù)據(jù)庫類型:B樹中剩、HASH表忌穿、記錄
typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;

//通用的數(shù)據(jù)庫句柄定義。
typedef struct __db {
    DBTYPE type;            /* 類型 */
    int (*close)(struct __db *);  //關(guān)閉庫函數(shù)
    int (*del)(const struct __db *, const DBT *, unsigned int);  //刪除元素函數(shù)
    int (*get)(const struct __db *, const DBT *, DBT *, unsigned int);  //獲取元素函數(shù)
    int (*put)(const struct __db *, DBT *, const DBT *, unsigned int); //設(shè)置元素函數(shù)
    int (*seq)(const struct __db *, DBT *, DBT *, unsigned int); //序列號生成函數(shù)
    int (*sync)(const struct __db *, unsigned int);  //同步函數(shù)
    void *internal;         /* 內(nèi)部結(jié)構(gòu) */
    int (*fd)(const struct __db *);   //得到文件描述符函數(shù)
} DB;

而我們使用的key-value庫內(nèi)部其實是一種DB_HASH類型的數(shù)據(jù)庫文件结啼。同時DBM類型其實也是一種DB類型伴网。因此當(dāng)我們需要進行磁盤同步時只需要將DBM類型的句柄轉(zhuǎn)化為DB類型的句柄,然后調(diào)用其中sync函數(shù)就可以實現(xiàn)磁盤文件的同步了妆棒。這樣我們就可以在需要將內(nèi)存數(shù)據(jù)保存到磁盤是直接調(diào)用同步函數(shù)而不需要通過關(guān)閉文件來達到磁盤存儲的目的澡腾。

示例代碼:

  DBM *dbm = XXX;  //假設(shè)DBM是在其他地方打開的數(shù)據(jù)庫文件句柄.
  DB *db = (DB*)dbm;  //轉(zhuǎn)化為DB類型指針。
  db->sync(db, 0);  //這里調(diào)用這個函數(shù)就可以實現(xiàn)內(nèi)存數(shù)據(jù)到磁盤的同步處理了糕珊。

遍歷

功能:系統(tǒng)提供了兩個遍歷的函數(shù)动分,分別是獲取整個數(shù)據(jù)庫中最開始的key值,以及獲取下一個有效的key值的函數(shù).
函數(shù)簽名:

//獲取第一個存儲的key值红选。
 datum dbm_firstkey(DBM *db);

//獲取下一個存儲的key值澜公。
 datum dbm_nextkey(DBM *db);

參數(shù)
db:[in]數(shù)據(jù)庫句柄
return: 返回對應(yīng)的key值,如果沒有key值那么返回的結(jié)構(gòu)體中的dptr的值將是NULL喇肋。

描述
你可以通過這兩個函數(shù)來依次遍歷整個數(shù)據(jù)庫中的key值坟乾,然后再結(jié)合dbm_fetch來獲取對應(yīng)的value。需要注意的是如果某次遍歷期間中執(zhí)行了插入或者刪除操作則應(yīng)該要重新進行遍歷蝶防,否則得到的結(jié)果未可知甚侣。

示例代碼:

//遍歷函數(shù)
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);
    
     //關(guān)閉 
    dbm_close(dbm);
}

在iOS系統(tǒng)的內(nèi)部實現(xiàn)中所有的添加或者刪除操作如果不執(zhí)行dbm_close的話那么都不會實際保存到磁盤文件中。因此如果你在iOS系統(tǒng)中使用這套API則要記得在合適的時候執(zhí)行數(shù)據(jù)庫關(guān)閉處理间学。當(dāng)然你也可以通過上述提供的磁盤同步的方法來實現(xiàn)內(nèi)存到磁盤的保存處理殷费。

有一些Unix系統(tǒng)中對key-value的長度限制為1024而有些系統(tǒng)則沒有這個限制。

下一篇:iOS標(biāo)準(zhǔn)庫中常用數(shù)據(jù)結(jié)構(gòu)和算法之位串


歡迎大家訪問歐陽大哥2013的github地址簡書地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末低葫,一起剝皮案震驚了整個濱河市详羡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘿悬,老刑警劉巖实柠,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異善涨,居然都是意外死亡窒盐,警方通過查閱死者的電腦和手機茶行,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來登钥,“玉大人,你說我怎么就攤上這事娶靡∧晾危” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵姿锭,是天一觀的道長塔鳍。 經(jīng)常有香客問我,道長呻此,這世上最難降的妖魔是什么轮纫? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮焚鲜,結(jié)果婚禮上掌唾,老公的妹妹穿的比我還像新娘。我一直安慰自己忿磅,他們只是感情好糯彬,可當(dāng)我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著葱她,像睡著了一般撩扒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吨些,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天搓谆,我揣著相機與錄音,去河邊找鬼豪墅。 笑死泉手,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的偶器。 我是一名探鬼主播螃诅,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼状囱!你這毒婦竟也來了术裸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤亭枷,失蹤者是張志新(化名)和其女友劉穎袭艺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叨粘,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡猾编,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年瘤睹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片答倡。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡轰传,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瘪撇,到底是詐尸還是另有隱情获茬,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布倔既,位于F島的核電站恕曲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏渤涌。R本人自食惡果不足惜佩谣,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望实蓬。 院中可真熱鬧茸俭,春花似錦、人聲如沸安皱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽练俐。三九已至袖迎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間腺晾,已是汗流浹背燕锥。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留悯蝉,地道東北人归形。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像鼻由,于是被迫代替她去往敵國和親暇榴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容