上一篇: 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)和算法之位串