fskv - kv数据库,掉电不丢数据
作者:马亚丹
一、概述
fskv 核心库是操作合宙 LuatOS 系统中的键值对(Key-Value)数据库的库,旨在替代旧的 fdb 库,并兼容 fdb 的函数,同时使用 fdb 的 Flash 空间。其作用是在 Flash 存储器中持久化存储键值对数据,允许开发者以键值对的形式存储和检索数据,并且这些数据会被持久化存储在 Flash 存储器上,确保设备断电后数据不会丢失。适用于物联网设备的配置信息、传感器数据等场景应用。
核心特点:
- 持久化存储:数据写入 Flash,断电后不丢失;
- 功能丰富:提供 fskv.init()(初始化)、fskv.set(key, value)(存储数据)、fskv.get(key)(读取数据)、fskv.del(key)(删除数据)等 API;
- 稳定高效:读写速度恒定,不受 “脏数据” 影响,最高 10 万次均衡擦写;
- 优化数据长度限制:如 value 最大 4096 字节,key 最大 63 字节。
合宙 fskv 核心库原理是在模组片上 flash 单独开辟了一个小区域,跑了个小文件系统,单独操作,实现类似于微型数据库的功能,只支持操作芯片自身的 flash 文件系统,不支持操作通过 lf 核心库或者 sfud 核心库挂载的文件系统。
简单说,fskv 核心库就是一个 “嵌入式设备里的小数据库”,专门用来安全、稳定地存放大块配置或业务数据,断电也不会丢。
二、核心示例
1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;
2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/fskv
local function fskv_test()
-- 设置数据, 字符串,数值,table,布尔值,均可
-- 但不可以是nil, function, userdata, task
fskv.set("my_bool", true)
fskv.set("my_int", 123)
fskv.set("my_number", 1.23)
fskv.set("my_str", "luatos")
fskv.set("my_table", { name = "wendal", age = 18 })
log.info("fskv", "获取my_bool", type(fskv.get("my_bool")), fskv.get("my_bool"))
log.info("fskv", "获取my_int", type(fskv.get("my_int")), fskv.get("my_int"))
log.info("fskv", "获取my_number", type(fskv.get("my_number")), fskv.get("my_number"))
log.info("fskv", "获取my_str", type(fskv.get("my_str")), fskv.get("my_str"))
log.info("fskv", "获取my_table", type(fskv.get("my_table")), json.encode(fskv.get("my_table")))
if fskv.sett then
-- 设置数据, 字符串,数值,table,布尔值,均可
-- 但不可以是nil, function, userdata, task
log.info("fskv", fskv.sett("mytable", "wendal", "goodgoodstudy"))
log.info("fskv", fskv.sett("mytable", "upgrade", true))
log.info("fskv", fskv.sett("mytable", "timer", 1))
log.info("fskv", fskv.sett("mytable", "bigd", { name = "wendal", age = 123 }))
-- 下列语句将打印出4个元素的table
log.info("fskv", "获取mytable1", fskv.get("mytable"))
log.info("fskv", "获取mytable1", fskv.get("mytable"), json.encode(fskv.get("mytable")))
-- 删除测试
log.info("fskv", fskv.sett("mytable", "nameage", { age = 18, name = "wendal" }))
log.info("fskv", fskv.sett("mytable", "name"))
log.info("fskv", "获取mytable2", fskv.get("mytable"), json.encode(fskv.get("mytable")))
end
--根据KV迭代器获取key值
local iter = fskv.iter()
log.info("kv数据库迭代器", iter)
if iter then
while 1 do
local k = fskv.next(iter)
log.info("kv迭代器获取下一个key", k)
if not k then
break
end
log.info("fskv", k, "value", fskv.get(k))
end
end
--查询kv数据库状态
local used, total, kv_count = fskv.status()
log.info("获取kv数据库状态", "fskv", "kv", used, total, kv_count)
log.info("清空整个kv数据库", fskv.clear())
local used, total, kv_count = fskv.status()
log.info("获取kv数据库状态", "fskv", "kv", used, total, kv_count)
end
sys.taskInit(fskv_test)
三、常量详解
核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
fskv 核心库库,没有常量。
四、函数详解
4.1 fskv.init()
功能
初始化 kv 数据库
注意事项
暂无
参数
无
返回值
local result= fskv.init()
有一个返回值 result
result
含义说明:初始化kv数据库;
成功时返回true,否则返回false
数值类型:boolean
取值范围:true/false
注意事项:初始化失败时,需做好对应逻辑处理
返回示例:例如返回true时表示初始化kv数据库成功
示例
local result= fskv.init()
if result then
log.info("fskv", "kv数据库初始化成功",result)
end
4.2 fskv.set(key, value)
功能
设置一对 kv 数据
注意事项
value 参数不能设为 nil、 function、 userdata、task 类型;
参数
key
参数含义:键的名称,即kv数据的key的名称
数据类型:string
取值范围:长度1~63字节
是否必选:必须传入此参数;
注意事项:不能是空字符串
参数示例:--如下所示,"wendal"即是设置kv数据时的key的名称
log.info("fskv", fskv.set("wendal", "goodgoodstudy"))
value
参数含义:用户数据
数据类型:string/number/table/boolean
取值范围:长度1~4095字节
是否必选:必须传入此参数;
注意事项:参数不能设为nil、 function、 userdata、task;
可以是字符串/数值/table/布尔值, 数据长度最大4095字节
参数示例:--如下所示,"goodgoodstudy"即是设置kv数据时的用户数据
log.info("fskv", fskv.set("wendal", "goodgoodstudy"))
返回值
local result= fskv.set(key, value)
有一个返回值 result
result
含义说明:设置一对kv数据;
成功时返回true,否则返回false
数值类型:boolean
取值范围:true/false
注意事项:设置失败时,需做好对应逻辑处理
返回示例:例如返回true时表示设置一对kv数据成功
示例
-- 设置用户数据, 字符串、数值、table、布尔值均可
-- 用户数据不可以是nil, function, userdata, task
--如下所示设置用户数据是字符串
log.info("fskv", fskv.set("wendal", "goodgoodstudy"))
--如下所示设置用户数据是布尔值
log.info("fskv", fskv.set("upgrade", true))
--如下所示设置用户数据是数值
log.info("fskv", fskv.set("timer", 1))
--如下所示设置用户数据是table
log.info("fskv", fskv.set("bigd", {name="wendal",age=123}))
4.3 fskv.sett(key, skey, value)
功能
设置 table 内的键值对数据
注意事项
value 参数不能设为 nil、 function、 userdata、task 类型;
参数
key
参数含义:键的名称,即kv数据的key的名称
数据类型:string
取值范围:长度1~63字节
是否必选:必须传入此参数;
注意事项:不能是空字符串
参数示例:--如下所示,"mytable"即是设置table内的键值对数据时的key的名称
log.info("fskv", fskv.sett("mytable", "wendal", "goodgoodstudy"))
skey
参数含义:table的key名称
数据类型:string
取值范围:长度1~63字节
是否必选:必须传入此参数;
注意事项:不能是空字符串
参数示例:--如下所示,"wendal"即是设置table内的键值对数据时的skey的名称
log.info("fskv", fskv.sett("mytable", "wendal", "goodgoodstudy"))
value
参数含义:用户数据
数据类型:string/number/table/boolean
取值范围:nil,长度1~4095字节
是否必选:必须传入此参数;
注意事项:参数不能 function、 userdata、task;
可以是字符串/数值/table/布尔值, 数据长度最大4095字节,
如果设为nil代表删除对应的key
参数示例:--如下所示,"goodgoodstudy"即是设置table内的键值对数据时的value
log.info("fskv", fskv.sett("mytable", "wendal", "goodgoodstudy"))
返回值
local result= fskv.sett(key, skey, value)
有一个返回值 result
result
含义说明:设置table内的键值对数据;
成功时返回true,否则返回false/nil
数值类型:boolean
取值范围:true/false/nil
注意事项:设置失败时,需做好对应逻辑处理
返回示例:例如返回true时表示设置table内的键值对数据成功
示例
-- 设置用户数据, 字符串、数值、table、布尔值均可
-- 用户数据不可以是function, userdata, task
-- 用户数据设为nil代表删除对应的key
--如下所示设置用户数据是字符串
log.info("fskv", fskv.sett("mytable", "wendal", "goodgoodstudy"))
--如下所示设置用户数据是布尔值
log.info("fskv", fskv.sett("mytable", "upgrade", true))
--如下所示设置用户数据是数值
log.info("fskv", fskv.sett("mytable", "timer", 1))
--如下所示设置用户数据是table
log.info("fskv", fskv.sett("mytable", "bigd", {name="wendal",age=123}))
-- 下列语句将打印出上面4个元素的table
--log打印 I/user.fskv mytable table: 0C7F5C30 table: 0C7F60F8 {"bigd":{"name":"wendal","age":123},"wendal":"goodgoodstudy","timer":1,"upgrade":true}
log.info("fskv", fskv.get("mytable"), json.encode(fskv.get("mytable")))
----
-- 注意: 如果key不存在, 或者key已存在但是原本的值不是table类型,再次设置同样key时原来的值将会完全覆盖
-- 例如下列两行的写法,最终获取到的是table 即{age:"123"},而非第一行的字符串123
log.info("fskv", fskv.set("mykv", "123"))
-- 保存的将是 {age:"123"}
log.info("fskv", fskv.sett("mykv", "age", "123"))
----
----
-- 如果设置value用户数据为nil, 代表删除对应的key
--log打印 I/user.fskv true
--log打印 I/user.fskv删除
log.info("fskv", fskv.sett("mykv", "name", "wendal"))
log.info("fskv删除", fskv.sett("mykv", "name"))
----
4.4 fskv.get(key, skey)
功能
根据 key 获取对应的数据
注意事项
暂无
参数
key
参数含义:键的名称,即kv数据的key的名称
数据类型:string
取值范围:长度1~63字节
是否必选:必须传入此参数;
注意事项:不能是空字符串
参数示例:--如下所示,fskv.get("wendal")中的参数"wendal"即是获取数据时的key的名称
--log打印 I/user.fskv goodgoodstudy
log.info("fskv", fskv.set("wendal", "goodgoodstudy"))
log.info("fskv", fskv.get("wendal"))
-- 若需要"默认值", 对应非bool布尔值, 可以这样写
local v = fskv.get("wendal") or "123"
skey
参数含义:次级key,仅当原始值为table时有效,相当于 fskv.get(key)[skey]
数据类型:string
取值范围:长度1~63字节
是否必选:非必须传入此参数;
注意事项:暂无
参数示例:--如下所示,fskv.get("mytable", "wendal")中的参数"wendal"即是获取数据时的 key的名称,
--log打印 I/user.fskv goodgoodstudy
log.info("fskv", , fskv.sett("mytable", "wendal", "goodgoodstudy"))
log.info("fskv", fskv.get("mytable", "wendal"))
返回值
不带 skey 参数的写法
fskv.set("wendal","goodgoodstudy")
local v= fskv.get("wendal")
有一个返回值 v
v
含义说明:与key对应的数据;
数据存在则返回数据,否则返回nil
数值类型:any
取值范围:无特别限制
注意事项:未获取失败数据时,需做好对应逻辑处理
返回示例:例如返回 goodgoodstudy时表示获取数据成功
带 skey 参数的写法
fskv.sett("mytable", "wendal", "goodgoodstudy")
local v= fskv.get("mytable","wendal")
有一个返回值 v
v
含义说明:与skey对应的数据;
数据存在则返回数据,否则返回nil
数值类型:any
取值范围:无特别限制
注意事项:未获取失败数据时,需做好对应逻辑处理
返回示例:例如返回 goodgoodstudy时表示获取数据成功
示例
-- 例如下列写法,最终获取到的是数据123
log.info("fskv", fskv.set("mykv", "123"))
log.info("fskv", fskv.get("mykv"))
log.info("fskv", fskv.set("bigd", {name="wendal",age=123}))
-- 例如下列写法,最终获取到的是table: 0C7F6798
log.info("fskv", fskv.get("bigd"))
-- 例如下列写法,最终获取到的是wendal
log.info("fskv", fskv.get("bigd","name"))
-- 例如下列写法,最终获取到的是123
log.info("fskv", fskv.get("wendal") or "123")
4.5 fskv.del(key)
功能
根据 key 删除数据
注意事项
暂无
参数
key
参数含义:键的名称,即kv数据的key的名称
数据类型:string
取值范围:长度1~63字节
是否必选:必须传入此参数;
注意事项:不能是空字符串
参数示例:--如下所示,"wendal"即是删除kv数据时的key的名称
log.info("fskv", fskv.del("wendal"))
返回值
local result= fskv.del("wendal")
有一个返回值 result
result
含义说明:删除一对kv数据;
成功时返回true,否则返回false
数值类型:boolean
取值范围:true/false
注意事项:返回失败时,需做好对应逻辑处理
返回示例:例如返回true时表示删除一对kv数据成功
示例
log.info("fskv", fskv.set("wendal", "goodgoodstudy"))
--如下写法,删除上述设置的kv数据,返回true,表示删除成功
log.info("fskv", fskv.del("wendal"))
4.6 fskv.clear()
功能
清空整个 kv 数据库
注意事项
暂无
参数
无
返回值
local result= fskv.clear()
有一个返回值 result
result
含义说明:清空整个kv数据库;
成功时返回true,否则返回false
数值类型:boolean
取值范围:true/false
注意事项:返回失败时,需做好对应逻辑处理
返回示例:例如返回true时表示初始化kv数据库成功
示例
local result= fskv.clear()
if result then
log.info("fskv", "kv数据库清空成功",result)
end
4.7 fskv.iter()
功能
kv 数据库迭代器
注意事项
该接口作用是创建一个 “迭代器指针”(可以理解为 “遍历的起始游标”)。
再通过 fskv.next(iter)
配合这个指针,就能逐个获取 KV 数据库中的键(当返回 nil
时,表示遍历完所有键)。
这样你就可以通过 “迭代器 + next 方法” 的组合,遍历整个 KV 数据库的所有键值对(拿到键后,再通过 fskv.get
等方法取对应值),而不需要关心 KV 数据库内部是如何存储的。
参数
无
返回值
local iter = fskv.iter()
log.info("kv数据库迭代器", iter)
有一个返回值 iter
iter
含义说明:kv数据库迭代器;
成功返回迭代器指针,否则返回nil
数值类型:userdata
取值范围:无特别限制
注意事项:返回失败时,需做好对应逻辑处理
返回示例:例如返回userdata: 0C7F5158时表示获取kv数据库迭代器成功
示例
local iter = fskv.iter()
log.info("kv数据库迭代器", iter)
4.8 fskv.next(iter)
功能
根据 kv 迭代器指针获取下一个 key
注意事项
暂无
参数
iter
参数含义:kv迭代器,fskv.iter()返回的指针
数据类型:userdata
取值范围:无特别限制
是否必选:必须传入此参数;
注意事项:不能是空字符串
参数示例:--如下所示,"iter"即是获取下一个key时的kv迭代器指针
local k = fskv.next(iter)
返回值
local k = fskv.next(iter)
有一个返回值 k
k
含义说明:根据kv迭代器指针获取的下一个key;
成功返回字符串key值, 否则返回nil
数值类型:string
取值范围:1~63字节
注意事项:返回失败时,需做好对应逻辑处理
返回示例:例如按照4.2fskv.set(key, value)的示例设置了4对kv数据,下方示例返回upgrade等key时表示获取到下一个key成功
示例
local iter = fskv.iter()
log.info("kv数据库迭代器", iter)
if iter then
while 1 do
local k = fskv.next(iter)
log.info("kv迭代器获取下一个key", k)
if not k then
break
end
log.info("fskv", k, "value", fskv.get(k))
end
end
4.9 fskv.status()
功能
获取 kv 数据库状态
注意事项
暂无
参数
无
返回值
local used, total,kv_count = fskv.status()
有三个返回值 used, total,kv_count
used
含义说明:已使用的空间,单位字节;
成功时返回已使用空间大小
数值类型:int
取值范围:0~65536
注意事项:返回失败时,需做好对应逻辑处理
返回示例:例如返回8192时表示已使用8192字节的空间
total
含义说明:总可用空间, 单位字节;
成功时返回总可用空间大小
数值类型:int
取值范围:65536
注意事项:支持LuatOS的合宙模组总可用fskv空间是64K
返回示例:例如返回65536时表示总可用空间是65536字节
kv_count
含义说明:总kv键值对数量, 单位个;
成功时返回总kv键值对数量,
数值类型:int
取值范围:0~?
注意事项:暂无
返回示例:例如返回8时表示已存在8对KV数据
示例
-- log打印 I/user.获取kv数据库状态 fskv kv 8192 65536 10
local used, total, kv_count = fskv.status()
log.info("获取kv数据库状态", "fskv", "kv", used, total, kv_count)
五、产品支持说明
支持 LuatOS 开发的所有产品都支持 fskv 核心库。