iOS標準庫中經常使用數據結構和算法之KV數據庫

上一篇: iOS標準庫中經常使用數據結構和算法之哈希表算法

💾KV數據庫

對於結構化數據的存儲通常咱們使用關係型數據庫,而對於基於key-value類型的數據存儲則不適合用關係型數據庫。所以iOS系統也內置了一套基於key-value存儲的文件數據庫:ndbm。數據庫

功能: 一套基於key-value形式存儲的數據庫。bash

頭文件: #include <ndbm.h>數據結構

平臺: BSD Unixapp

1、建立、打開、關閉

功能: 數據庫文件的建立、打開、關閉。數據結構和算法

函數簽名函數

//數據庫文件的建立或者打開
DBM * dbm_open(const char *file, int open_flags, mode_t file_mode);
//數據庫文件的關閉
void  dbm_close(DBM *db);

複製代碼

參數:post

file:[in] 指定數據庫的文件名,系統在打開和建立時會在內部自動添加.db的後綴名稱,所以咱們不須要指定後綴擴展名部分。fetch

open_flags: [in] 文件的打開屬性,通常傳遞O_RDWR | O_CREAT 代表讀寫以及不存在時建立。ui

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時代表插入失敗。

3、刪除

功能: 從數據庫中刪除某個key-value鍵值對。

函數簽名:

int dbm_delete(DBM *db, datum key);

複製代碼

參數:

db: [in] 數據庫句柄。

key:[in] 要刪除的鍵。

return:[out] 若是返回0則刪除成功,返回1則代表不存在指定的key,返回-1則是其餘錯誤。

4、查詢

功能: 根據指定的key從數據庫中查找對應的value值。

函數簽名:

datum dbm_fetch(DBM *db, datum key);

複製代碼

參數

db:[in] 數據庫句柄。

key:[in] 查找指定的key

return:[out] 系統返回一個結構體datum, 存儲返回的value值。若是key沒有對應的value 值, 那麼返回的datum中的dptr的值將是NULL。咱們不須要對返回的值進行內存釋放,也不能對返回的值的內容進行修改。

5、磁盤同步

功能: 將內存中保存的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);  //這裏調用這個函數就能夠實現內存數據到磁盤的同步處理了。

複製代碼

6、遍歷

功能:系統提供了兩個遍歷的函數,分別是獲取整個數據庫中最開始的key值,以及獲取下一個有效的key值的函數.

函數簽名:

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

//獲取下一個存儲的key值。
 datum dbm_nextkey(DBM *db);
複製代碼

參數

db:[in]數據庫句柄

return:[out] 返回對應的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而有些系統則沒有這個限制。

相關文章
相關標籤/搜索