Lua:何时以及如何写表格

我正在从书中学习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

'writeToFile'在尝试写入_G [resTable [i]]时出错,在这里列出的两个函数中,我不明白他们为什么引用_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函数执行脚本来读取它们。 它的主要限制是它只能保存字符串,布尔值是一个数字,但通常在学习时这就足够了。

    您可以使用以下语句对其进行测试:

    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页面。


    这些不是通用的“从/到任何文件读/写任何表”功能。 他们显然期望全局表的名称作为参数,而不是[引用本地]表本身。 它们看起来像是一种一次性的解决方案,可以解决一个非常具体的问题,这种问题往往会出现在书本中。 :-)

    你的功能不应该对_G做任何事情。 我没有方便的API参考,但是阅读循环应该做类似的事情

    resTable[a] = line
    

    写循环会做

    hfile:write(resTable[i])
    

    也扔掉当地的“结果”表。 :-)


    此代码读取和写入文件中的数据到名称在aryTable中指定的全局变量中。 由于你的文件是空的, readFromFile实际上不设置变量值。 然后writeToFile在尝试获取变量值时失败,因为它们尚未设置。

    尝试将数据放入文件中,以便变量确实被设置,或者在将变量值写入文件之前自行设置变量值(例如Score = 10等)

    链接地址: http://www.djcxy.com/p/16473.html

    上一篇: Lua: When and how to write tables to

    下一篇: MSBuild locking dll used on T4 template generated on build