Lua: When and how to write tables to

I am learning Lua from a book, and I am NOT a programmer. I am trying to save a table of data to a file using the following functions (that were copied directly from the book), but the function is getting an error when trying to get a string from _G[resTable]. Why?

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" gets an error when trying to :write to _G[resTable[i]]. In the two previous functions listed here, I don't understand why they are referencing _G[resTable[i]] since I don't see any code that is writing to _G.

So here is the order of execution:

local aryTable = {
"Score",
"Lives",
"Health",
}

readFromFile("datafile", aryTable)

writeToFile("datafile", aryTable)

and I get an error:

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

Apparently the author has implemented a way of saving a list of global variables to file and restore them.

The function writeToFile expects a filename and a list of global variables names ( resTable ). Then it opens a the filename for writing and iterates over the provided names:

for i=1, #resTable do
    hfile:write(_G[resTable[i]])
end

in this loop resTable[i] is the i-th name and _G[resTable[i]] is the corresponding value, taken from the table _G , which stores all the globals. If a global with that name is not defined, _G[resTable[i]] will return nil , which is the cause of the failure you experienced. Thus you must provide a resTable that is filled with names of existing globals to avoid this error.

Apart from this, the serialization strategy of the author is really naive, since it handles only variables with string values. In fact by saving the variables to file like that the type information is lost, thus a variable having the value "100" (a string) and another with value 100 (a number) will be stored the same on disk.

The problem is evident analyzing the readFromFile function. After opening the file for reading, it scans it line by line, creating a new variable for each name mentioned in its resTable list:

local a = 1
for line in hfile:lines() do
    _G[resTable[a]] = line
    a = a + 1
end

the problem is manyfold:

  • the loop variable line will always have a string value, thus the recreated globals will be all strings, even if they were numbers originally;
  • it assumes that the variables are recreated in the same order, thus you must provide the same names in resTable you used when you saved the file;
  • it assumes that the values are stored one per line, but this is a false assumption, since the writeToFile function doesn't write a newline character after each value;
  • Moreover that local results = {} is useless and in both functions the file handle hfile is not closed. This latter is very bad practice: it could waste system resources and if your script fails part of the supposedly written data could never make its way to disk, since it may be still stuck in some buffer. File handles are automatically closed when the script ends, but only if it ends in a sane way.

    Unless you did some error in pasting the code or omitted significant parts of it or the book is building some example incrementally, I dare say it is fairly crappy.


    If you want a quick and dirty way to save and retrieve some globals you could use this:

    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
    

    It saves the globals as a Lua script and reads them back by executing the script using Lua dofile function. Its main limitation is that it can only save strings, booleans an numbers, but usually this is enough while learning.

    You can test it with the following statements:

    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 )
    

    If you need more advanced serialization techniques you can refer to Lua WIKI page on table serialization.


    Those aren't generalized "read/write any table from/to any file" functions. They apparently expect the name of a global table as an argument, not a [reference to a local] table itself. They look like the kind of one-off solution to a very specific problem that tends to show up in books. :-)

    Your functions shouldn't be doing anything with _G. I don't have an API reference handy, but the read loop should be doing something like

    resTable[a] = line
    

    and the write loop would be doing

    hfile:write(resTable[i])
    

    Throw out that local "results" table too. :-)


    This code reads and writes data from a file into global variables whose names are specified in aryTable . Since your file is empty, readFromFile does not actually set the variable values. And then writeToFile fails when trying to get the variable values, because they haven't been set.

    Try putting data in the file so that the variables do get set, or set the variable values yourself before writing them to the file (eg Score = 10 , etc.)

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

    上一篇: 在DOM元素之后移动选区

    下一篇: Lua:何时以及如何写表格