SoFunction
Updated on 2025-04-08

Lua Tutorial (Eight): Data Persistence

1. Data file:

We can use the table constructor in Lua to define a file format, that is, the data in the file is the code constructed and initialized by table. This method is very convenient and clear for Lua programs, such as:
 

Copy the codeThe code is as follows:

    Entry { "Stephen Liu", "Male", "Programmer", "BS" }
    Entry { "Jerry Tian", "Male", "Programmer", "BS" }
 

It should be noted that Entry{<code>} is equivalent to Entry({<code>}). For the above data entry, if we can define a suitable Entry function, we can make this data a part of our Lua code. See the following code and its comments:
Copy the codeThe code is as follows:

local count = 0
--The Entry function is predefined here so that when executing the data code in the dofile, the matching function can be found.
function Entry() count = count + 1 end
dofile("d:/lua_data.conf")
print("number of entries: " .. count)

--The output result is:
--number of entries: 2

Compared to the format of the data file above, we can also define a clearer "self-described data" format, where each item of data is accompanied by a short description that indicates its meaning. With this format, even if the data items change in the future, we can still maintain backward compatibility with minimal changes. See the following data format and related code:

Copy the codeThe code is as follows:

    Entry { name = "Stephen Liu", gender = "Male", job = "Programmer", education = "BS" }
    Entry { name = "Jerry Tian", gender = "Male", job = "Programmer", education = "BS" }

Copy the codeThe code is as follows:

local personInfo = {}
function Entry(b)
-- Here, the name field value of table object b is used as the key information of personInfo.
    if then
        personInfo[] = true
    end
end

dofile("d:/lua_data.conf")
for name in pairs(personInfo) do
    print(name)
end

--The output result is:
--Jerry Tian
--Stephen Liu

It can be seen that these code snippets adopt event-driven approach. The Entry function acts as a callback function and is called for each entry in the data file when executing a dofile.

Lua not only runs fast, but also compiles fast. This is mainly because Lua used data description as one of Lua's main applications at the beginning of design.
    
2. Serialization:

I believe that people with Java or C# development experience are no strangers to this term. It is to convert the data object into a byte stream and output it to a file or network through IO, and then reconstruct the data into a new object with the same value as the original object. Or we can use an executable Lua code as the serialized data format. For example: varname = <expr>, where <expr> represents the expression that calculates the variable varname. The following example code is used to serialize a ring-free table:
 

Copy the codeThe code is as follows:

 function serialize(o)
    if type(o) == "number" then
        (o)
    elseif type(o) == "string" then
--The "%q" parameter of the function can escape metacharacters in a string.
        (("%q",o))
    elseif type(o) == "table" then
        ("{\n")
--Iterate over each element in the table, and at the same time recursively write out the value of each field.
-- From this we can see that this simple example can support nested tables.
        for k,v in pairs(o) do
--This is done to prevent k from including illegal Lua identifiers.
            (" ["); serialize(k); ("] = ")
            serialize(v)
            (",\n")
        end
        ("}\n")
    else
        error("cannot serialize a " .. type(o))
    end
end