我正在从书中学习Lua,但我不是程序员。我正在尝试使用以下功能(直接从书中复制)将数据表保存到文件中,但是当尝试从_G [resTable]获取字符串时,该功能出现错误。为什么?
function readFromFile(filename,resTable)
local hfile = io.open(filename)
if hfile == nil then return end
local results = {} -why is this table here?
local a = 1
for line in hfile:lines() do-- debug shows this loop doesn't run (no lines in hfile?)
_G[resTable[a]] = line
a = a + 1
end
end
function writeToFile(filename, resTable)
local hfile = io.open(filename, "w")
if hfile == nil then return end
local i
for i=1, #resTable do
hfile:write(_G[resTable[i]])--bad argument #1 to 'write' (string expected, got nil)
end
end
尝试对_G [resTable [i]]进行写操作时'writeToFile“出现错误。在此处列出的前两个函数中,我不明白为什么它们引用_G [resTable [i]],因为我看不到正在写入_G的任何代码。
因此,这是执行顺序:
local aryTable = {
"Score",
"Lives",
"Health",
}
readFromFile("datafile", aryTable)
writeToFile("datafile", aryTable)
我得到一个错误:
bad argument #1 to 'write' (string expected, got nil)
stack traceback:
[C]: in function 'write'
test.lua:45: in function 'writeToFile'
test.lua:82: in main chunk
最佳答案
显然,作者实现了一种保存全局变量列表到文件并将其还原的方法。
函数writeToFile
需要一个文件名和一个全局变量名称列表(resTable
)。然后,它打开一个用于写入的文件名并遍历提供的名称:
for i=1, #resTable do
hfile:write(_G[resTable[i]])
end
在此循环中,
resTable[i]
是第i个名称,而_G[resTable[i]]
是对应的值,该值取自表_G
,该表存储所有全局变量。如果未定义具有该名称的全局变量,_G[resTable[i]]
将返回nil
,这是您遇到失败的原因。因此,您必须提供一个resTable
并填充现有全局变量的名称,以避免出现此错误。除此之外,作者的序列化策略真的很幼稚,因为它仅处理具有字符串值的变量。实际上,通过像丢失类型信息一样将变量保存到文件中,因此具有
"100"
值(字符串)和具有100
值(数字)的变量将被存储在磁盘上。分析
readFromFile
函数可以明显看出问题。打开文件以进行读取后,它将逐行扫描它,并为其resTable
列表中提到的每个名称创建一个新变量:local a = 1
for line in hfile:lines() do
_G[resTable[a]] = line
a = a + 1
end
问题有很多:
line
将始终具有字符串值,因此重新创建的全局变量将全部为字符串,即使它们最初是数字也是如此。 resTable
中提供相同的名称; writeToFile
函数不会在每个值之后写入换行符; 此外,
local results = {}
是无用的,并且在两个函数中,文件句柄hfile
均未关闭。后者是非常不好的做法:它可能浪费系统资源,并且如果您的脚本失败,则假定写入的数据的某些部分将永远无法进入磁盘,因为它们仍可能卡在某些缓冲区中。脚本结束时,文件句柄将自动关闭,但前提是必须以合理的方式结束。除非您在粘贴代码时犯了一些错误或省略了代码的重要部分,或者除非本书正在逐步构建一些示例,否则我敢说它相当糟糕。
如果您想要一种快速而肮脏的方法来保存和检索某些全局变量,则可以使用以下方法:
function writeToFile( filename, resTable )
local hfile = io.open(filename, "w")
if hfile == nil then return end
for _, name in ipairs( resTable ) do
local value = _G[name]
if value ~= nil then
hfile:write( name, " = ")
local vtype = type( value )
if vtype == 'string' then
hfile:write( string.format( "%q", value ) )
elseif vtype == 'number' or vtype == 'boolean' then
hfile:write( tostring( value ) )
else
-- do nothing - unsupported type
end
hfile:write( "\n" )
end
end
hfile:close()
end
readFromFile = dofile
它将全局变量另存为Lua脚本,并通过使用Lua
dofile
函数执行脚本将其读回。它的主要限制是它只能保存字符串,对数字进行 bool(boolean) 运算,但是通常在学习时就足够了。您可以使用以下语句对其进行测试:
a = 10
b = "20"
c = "hello"
d = true
print( a, b, c, d )
writeToFile( "datafile", { "a", "b", "c", "d" } )
a, b, c, d = nil
print( a, b, c, d )
readFromFile( "datafile" )
print( a, b, c, d )
如果您需要更高级的序列化技术,可以引用Lua WIKI page on table serialization。