Lua 学习笔记(九) ——数据文件与持久性

本文深入探讨了Lua编程语言中数据文件的构造式、如何通过table实现文件结构化存储,并详细介绍了串行化操作,包括如何将数据序列化为字节流以方便写入文件中。同时,文章还提供了实例演示了如何处理有环结构的table,确保复杂数据结构的正确保存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随之Lua的学习,从要记的各种语句到现在编写像样点的代码,真心地觉得我们在成长着。这段时间努力的学习Lua其实是被3D游戏所吸引。有人喜欢玩游戏,有人喜欢做游戏,而我竟是被那绚丽的画面吸引了。

好了,开始今天的学习了。

一、数据文件

首先是数据文件,借由table构造式来定义一种文件格式,在这种格式中,每条数据记录表示为一个Lua构造式。在上一篇中的entry{}的db.lua文件就是table作为一种文件格式的例子。entry是调用的函数,而函数的定义则是在entry = entry1

现在又来例子了:

entry {"Donald E. Knuth", --entry是调用的函数
"Literate Programming",
"CSLI",
1992
}

entry {"Jon Bentley",
"More Programming Pearls",
"Addison-Wesley",
1990
}
保存为data.lua

我们调用这个文件:计算data.lua文件中调用了几次entry函数

local count = 0
function entry() count = count + 1 end
dofile("D:/Lua Program/data.lua") --我的data.lua存储的绝对路径,当然你也可以用相对路径了。
print("number of entries:" .. count)

这里的执行结果当然是2了

下面的例子则是打印data.lua文件中的人名

local authors = {}
function entry(b)
	authors[b[1]] = true --b[1] 表示第一个参数,即人名
end
dofile("D:/Lua Program/data.lua")
for name in pairs(authors) do
	print(name)
end
结果:

Donald E. Knuth
Jon Bentley
当然如果上面的数据文件改为:

entry {
author = "Donald E. Knuth",
title = "Literate Programming",
publisher = "CSLI",
year = 1992
}
那我们打印时,只用修改下面一句就可以了。这样做的好处就是人名在数据文件中不是第一个也能正确打印出来。
function entry(b)
	authors[b[1]] = true --改为authors[b.author] = true

end
二、串行化

串行化是将数据转换为一个字节流或字符流。这就是涉及如何写入到数据文件中的问题了。

serialize函数就是串行化操作。list是一个table。这个例子的用途是将list这个table串行化,以便可以更好的写入到数据文件中。

function serialize(o)
	if type(o) == "number" then -- o为number型,直接写入
		io.write(o)
	elseif type(o) == "string" then -- o为string型,将o加上“”
		io.write(string.format("%q",o)) --%q 用双引号来括住字符串
	elseif type(o) == "table" then -- 如果为无环的table,加上{};有环的table下面例子处理
		io.write("{\n")
		for k,v in pairs(o) do
			io.write(" "..k.."=")
			serialize(v)
			io.write(",\n")
		end
		io.write("}\n")
	else
		error("cannot serialize a "..type(o)) --不是这三种,我们不处理
	end
end

list = {
	title = "Tecgraf",
	org = "Computer Graphics Technology Group, PUC-Rio",
	url = "http://www.tecgraf.puc-rio.br",
	contact = "Waldemar Celes",
	description = "Tecgraf is the result of a partnership between of Rio de Janeiro",
	list1 = {
	"hellen",
	"dfasf"
	}
}

serialize(list) -- 将list串行化
执行结果:

{
 contact="Waldemar Celes",
 title="Tecgraf",
 list1={
 1="hellen",
 2="dfasf",
}
,
 url="http://www.tecgraf.puc-rio.br",
 description="Tecgraf is the result of a partnership between of Rio de Janeiro",
 org="Computer Graphics Technology Group, PUC-Rio",
}
看到这个结果,会发现以这样的格式写入到文件中,我们就可以对其进行操作,如同打印title等。

上面对于有环的table处理未涉及,下面就来处理。

什么是有环,例如:

a = {x=1,y=2,{3,4,5}}
a[2] = a -- 环
a["z"] = a[1] -- 共享子table
那么怎样处理呢?
function basicSerialize(o) -- 串行化
	if type(o) == "number" then
		return tostring(o)
	else --o不是数字就只是string型
		return string.format("%q",o)
	end
end

function save(name,value,saved)
	saved = saved or {} -- 初始化saved
	io.write(name,"=")
	if type(value) == "number" or type(value) == "string" then
		io.write(basicSerialize(value),"\n") -- 串行化number和string
	elseif type(value) == "table" then
		if saved[value] then -- 该value是否保存过
			io.write(saved[value],"\n") --保存过,使用以前的名字
		else
			saved[value] = name --为下次使用保持名字
			io.write("{}\n") --创建一个新的table
			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("cannot save a "..type(value))
	end
end<pre name="code" class="plain">a = {x=1,y=2,{3,4,5}}
a[2] = a
a["z"] = a[1]

save("a",a)


执行结果:
>lua -e "io.stdout:setvbuf 'no'" "serialize.lua" 
a={}
a[1]={}
a[1][1]=3
a[1][2]=4
a[1][3]=5
a[2]=a
a["y"]=2
a["x"]=1
a["z"]=a[1]
>Exit code: 0

本文要说明的是用Lua以一种文件格式来存储数据文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值