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.