首頁 > 軟體

Ruby使用GDBM操作DBM資料儲存方法範例詳解

2022-04-18 22:02:21

DBM簡介

dbm(database manager) 是使用本地檔案來儲存資料的資料庫,基於Key -Value對資料進行儲存、讀取,且有些dbm的實現( berkeley db)還支援BTree索引。dbm效率相對較高,甚至在某些情況下比關係型資料庫系統的速度還更高,因為幾乎所有dbm都支援比BTree效率要高的hash索引方式。

有多種dbm實現:標準dbm、ndbm( new dbm)、gdbm(GNU DBM)、sdbm( small dbm)、Berkeley db等, gdbm是對ndbm的擴充套件,它支援快取功能。

DBM資料儲存原理

  • dbm的資料存取基於key-value的hash格式
  • dbm/ndbm中,key單獨存放在一個檔案中,key+value存放在另一個檔案中。對於gdbm,則是key作為索引資料單獨存放在db檔案中的一個地方(索引區),key+value存放在db檔案中的另一個地方(資料區)
  • 為了高效率查詢,除了key作為索引單獨存放外,還額外存放key+value在db檔案中的偏移位置以及大小,使得可以直接seek()跳轉到指定位置處讀取指定大小的資料
  • 刪除記錄時,只是刪除索引區的key,資料區的key+value不方便刪除也沒必要刪除,資料區這段孤兒空間稱為保留空間或碎片空間,可以作為空閒空間留待後續複用
  • gdbm在執行讀取操作之後會將資料快取下來,因此,第一次讀取可能速度慢,但是第二次速度將非常快。keys、values等操作的的結果也都會被快取下來
  • 因為碎片空間可被複用,所以dbm還會記錄所有的碎片空間的位置以及大小,gdbm中以連結串列方式記錄之
  • 因刪除記錄不會釋放空間,所以db檔案大小不會減小。換句話說,dbm的檔案會隨著時間的推移不斷增大,除非重組dbm,重組時,將根據索引區存在的key找到資料區所有對應的key+value資料,並將它們寫入臨時檔案,最後重新命名覆蓋原db檔案
  • 插入資料時,如果沒有碎片空間,預設將插入在尾部,如果中間有碎片空間,則判斷待寫入資料的大小是否能夠插入在碎片空間中
  • 更新資料時,如果更新後的資料變大,且該資料後面沒有碎片空間,則直接原地移除並在檔案尾部插入更新後的資料,如果有足夠的空間存放更新後的資料,則原地更新
  • dbm只能儲存字串,數值、布林、物件等都不能直接儲存

Ruby使用gdbm

Ruby中要使用gdbm,它依賴於gdbm擴充套件庫和標頭檔案,所以需先安裝:

# sudo yum install gdbm-devel
# Windows:
#   ridk exec uname -a確定32位元還是64位元,
#   然後ridk exec pacman -S mingw-w64-<$arch>-gdbm
sudo apt install libgdbm-dev
gem install gdbm

使用類方法GDBM.new()或者GDBM.open()可開啟gdbm來操作db檔案。

require 'gdbm'

gdbm = GDBM.new("/tmp/lang.db")
gdbm["perl"] = "Perl"
gdbm["shell"] = "Shell"
gdbm["php"] = "PHP"
gdbm.close

檢視其檔案內容:

$ ls -l /tmp/lang.db
-rw-rw-rw- 1 longshuai longshuai 8192 May 17 21:22 /tmp/lang.db

$ cat /tmp/lang.db
P |...x...l9php...rdshe...}N;iperl...perlPerlshellShellphpPHP

其中…表示的是亂碼部分。

注意其大小為8K,且資料區預設在db檔案的尾部,包含了key和value。

從db中檢索資料:

gdbm = GDBM.open("/tmp/lang.db")
pp gdbm["perl"]
pp gdbm["php"]
gdbm.close

new()、open()

new()或open():open()可給定語句塊,語句塊退出時自動關閉IO流,未給定語句塊時,open()等價於new()。

new(filename, mode = 0666, flags = nil)
open(filename, mode = 0666, flags = nil)
open(filename, mode = 0666, flags = nil) { |gdbm| ... }

當指定要操作的db檔案不存在時,會建立檔案,可指定建立檔案時的許可權。此外,flag引數接受如下值:

### 注意:writer方式可讀可寫
READER  - 以唯讀方式開啟,即返回一個reader
WRITER  - 以可讀寫方式開啟,即返回一個writer
WRCREAT - writer,如果資料庫檔案不存在,則建立
NEWDB   - writer,總是截斷覆蓋已存在的資料庫檔案

# 上面的三個writer可使用位或(|)的方式結合下面的選項:
SYNC   - 以sync模式寫入資料庫檔案
NOLOCK - 開啟時不鎖定資料庫檔案

在未給定任何選項時,即預設情況下,總是先嚐試以WRCREAT的方式開啟,即以writer開啟且檔案不存在時建立。但如果開啟失敗(比如另一個程序已經開啟且還未關閉),則嘗試使用reader方式開啟。

reader和reader之間互相相容,writer和writer之間以及writer和reader之間互斥。所以,在某一時刻,允許同時有多個reader,但只能有一個writer

當開啟gdbm範例後,它可以按照操作hash結構的方式去操作db,此外,gdbm已經mix-in Enumerable模組,所以可以直接使用該模組中的一些方法,比如find、grep、map等。

gdbm方法

######### 查詢、插入、更新 #########
["key"]
fetch(key [, default]) → value
檢索指定的key。
使用`[]`檢索時,如果key不存在將返回nil,
使用fetch檢索時,如果key不存在則報錯,或者返回指定的預設值

values_at(key, ...) → array
檢索一個或多個key,並以陣列方式返回對應的value

["key"]= value
store(key, value) → value
更新指定的key,如果key不存在則插入

########## 遍歷 #########
each_pair { |key, value| block } → gdbm
each_key { |key| block } → gdbm
each_value { |value| block } → gdbm
分別根據key-value、key、value遍歷db

######### 其它檢索、篩選方式 #########
key(value) → key
根據value找到其key,如果有多個相同的value,返回第一個

keys → array
以陣列方式返回db中所有的key

values → array
以陣列方式返回所有value

select { |key, value| block } → array
篩選所有滿足條件的key-value

######### 判斷key或value是否存在 #########
has_key?(k) → true or false
include?(k) → true or false
key?(k) → true or false
member?(k) → true or false
判斷key是否存在

has_value?(v) → true or false
value?(v) → true or false
判斷指定的value是否存在

######### 刪除 #########
delete(key) → value or nil
根據key移除key-value並返回被移除的Key-value,db若空,返回nil

shift → (key, value) or nil
移除指定的key-value,並以陣列方式返回之,db若空,則返回nil

delete_if { |key, value| block } → gdbm
移除滿足條件(語句塊返回true)的key-value,直接修改gdbm

reject { |key, value| block } → hash
等價於delete_if,但不修改gdbm,而是以hash的方式返回

reject! { |key, value| block } → gdbm
等價於delete_if,直接修改gdbm

clear → gdbm
清空db中所有key-value

######## 大小判斷 #########
empty? → true or false
db是否為空

length → fixnum
size → fixnum
等價,返回db中的key-value數量

####### 其它操作 #########
invert → hash
反轉gdbm中key-value:key作為value,value作為key,並以hash的方式返回

close → nil
關閉已開啟的db檔案

closed? → true or false
判斷db檔案是否已關閉

replace(other) → gdbm
將另一個gdbm(即other)的內容覆蓋替換到當前的gdbm

update(other) → gdbm
用另一個gdbm(即Other)合併到當前gdbm,若key衝突,則當前gdbm的key被覆蓋

reorganize → gdbm
重組gdbm

cachesize = size → size
設定gdbm內部的hash桶快取大小

######## gdbm模式 #########
sync → gdbm
將IO buffer中的資料刷入磁碟中的db檔案,全部寫入成功才返回
如果以SYNC標記開啟,則無需sync()

fastmode = boolean → boolean
syncmode = boolean → boolean
開啟或關閉sync模式。
sync模式下,寫入操作需要寫入磁碟db檔案成功(或失敗)後才返回,
非sync模式下,只需寫入io buffer即可返回。
syncmode方法在gdbm >= 1.8才可用,在此版本之前,使用方法fastmode=

######### 轉換 #########
to_a → array
to_hash → hash
轉換為陣列、轉換為hash

更多關於Ruby使用GDBM操作DBM資料儲存的方法請檢視下面的相關連結


IT145.com E-mail:sddin#qq.com