一、数据文件
如果在 Lua 程序中可以需要用文件保存数据,并且后续使用 Lua 进行读取使用,则可以考虑将数据按照一定的格式保存,然后用 dofile
函数进行加载,这样可以让数据很方便的进行读取。
我们可以将数据按照 EntryName{}
或者 EntryName({})
方式存储,这样一旦使用 dofile
加载,则会让数据文件解析为调用了 EntryName 函数,并且将 {}
内的内容解析为一个 table 作为一个参数传入函数。(在只有一个参数时,函数的调用携带参数是可以省略括号的)
dofile 的详细使用在下一篇文章进行分享
接下来通过完整的例子体会一下吧
数据文件的内容
lua
Entry{
"江澎涌",
"28",
1994,
}
Entry{
"小朋友",
"20",
2000
}
加载代码
lua
local count = 0
function Entry()
count = count + 1
end
-- 内部会调用 entry
dofile("/Users/jiangpengyong/Desktop/code/Lua/lua_study_2022/9 数据文件和序列化/data.txt")
print("number of entries: " .. count) --> number of entries: 2
数据文件中会调用 Entry
函数,并将 {}
作为入参,所以能做的事情很多,并不止局限于统计个数,也可以将数据收集,例如下面的代码,当然也可以做一些加工。
lua
local authors = {}
function Entry(author)
table.insert(authors, author)
end
-- 内部会调用 entry
dofile("/Users/jiangpengyong/Desktop/code/Lua/lua_study_2022/9 数据文件和序列化/data.txt")
for key, author in pairs(authors) do
print("key: ", key)
for key, value in pairs(author) do
print(key, "--", value)
end
end
--> key: 1
--> 1 -- 江澎涌
--> 2 -- 28
--> 3 -- 1994
--> key: 2
--> 1 -- 小朋友
--> 2 -- 20
--> 3 -- 2000
二、序列化为数据文件
在编写一个序列化工具中,需要注意的一些小点:
- string 类型要注意一些需要转义的字符,可以考虑使用
string.format("%q", content)
,会将特殊字符转义,并且能够很好的兼容数值、nil、boolean 类型。值得一提的是浮点数的数值会使用十六进制浮点数记录,保证他的精度。 - 如果不考虑使用
string.format("%q", content)
,则需要使用""
表示字符串,则需要注意代码注入 ,可以考虑[==[ .. ]==]
( = 可以是任意多个,具体可以翻阅字符串一章) 方式来表示长字符串。只是要兼容好字符串内容也存在长字符串的格式,可以使用比内容多一个=
的方式。 - 保存可能存在相互嵌套,但 Lua 的 table 构造器不支持嵌套,所以需要进行处理
2-1、不嵌套保存
对于不保存嵌套的 table ,可以使用以下代码,保存后的数据文件清晰明了
lua
function serialize(o)
local t = type(o)
if t == "number" or t == "string" or t == "boolean" or t == "nil" then
io.write(string.format("%q", o))
elseif t == "table" then
io.write("{\n")
for k, v in pairs(o) do
--- 第一种:这种做法能让 key = value 的形式比较直观,但带来的缺陷是一些关键字不能兼容
--io.write(" ", k, " = ")
--- 第二种:可读性比较差,以 ["key"] = value 形式保存,但是可以兼容所有关键字
io.write(" [")
serialize(k)
io.write("] = ")
serialize(v)
io.write(",\n")
end
io.write("}\n")
else
error(string.format("cannot serialize a %s", type(o)))
end
end
lua
print(serialize({ a = 12, b = 'Lua', key = 'another "one"' }))
--> {
--> ["b"] = "Lua",
--> ["a"] = 12,
--> ["key"] = "another \"one\"",
--> }
2-2、保存嵌套
lua
local function basicSerialize(o)
-- 对于 Lua 5.3.3 开始, %q 可以正常的显示字符串、 nil 、 数值(浮点数会使用十六进制进行保证精度)和 boolean 类型
return string.format("%q", o)
end
function save(name, value, saved)
saved = saved or {}
io.write(name, " = ")
if type(value) == "number"
or type(value) == "string"
or type(value) == "boolean"
or type(value) == "nil"
then
io.write(basicSerialize(value), "\n")
elseif type(value) == "table" then
if saved[value] then
io.write(saved[value], "\n")
else
saved[value] = name
io.write("{}\n")
for k, v in pairs(value) do
k = basicSerialize(k)
local fname = string.format("%s[%s]", name, k)
save(fname, v, saved)
end
end
else
error("can't save a " .. type(value))
end
end
lua
local table = {}
jiang = {}
xiao = {}
jiang[1] = xiao
xiao[1] = jiang
save("a", jiang, table)
--> a = {}
--> a[1] = {}
--> a[1][1] = a
三、写在最后
Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)
如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀。
公众号搜索 "江澎涌",更多优质文章会第一时间分享与你。