Lua Persistence Guide — Serialization and Data Storage Techniques
In this tutorial, you will learn about Lua Persistence Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Lua persistence techniques save and restore program state through table Serialization using string.format and loops, Lua script generation that reconstructs data on load, and file I/O patterns for configuration and Caching.
Table Serialization to String
function serialize(t)
local parts = {}
parts[#parts + 1] = "{"
for k, v in pairs(t) do
local key = type(k) == "string" and
string.format("[%q]", k) or k
local val
if type(v) == "table" then
val = serialize(v)
elseif type(v) == "string" then
val = string.format("%q", v)
else
val = tostring(v)
end
parts[#parts + 1] = string.format("%s = %s,", key, val)
end
parts[#parts + 1] = "}"
return table.concat(parts, "\n")
end
local data = {name = "Lua", version = 5.4, tags = {"scripting", "embed"}}
print(serialize(data))
Saving and Loading Tables
function saveTable(filename, t)
local f = io.open(filename, "w")
if not f then return false end
f:write("return ")
f:write(serialize(t))
f:close()
return true
end
function loadTable(filename)
local f = io.open(filename, "r")
if not f then return nil end
local content = f:read("*all")
f:close()
local chunk, err = load("return " .. content)
if not chunk then return nil, err end
return chunk()
end
Configuration Files
-- config.lua file:
-- return {
-- host = "localhost",
-- port = 8080,
-- debug = true
-- }
-- Loading config
local config = dofile("config.lua")
print(config.host) --> localhost
print(config.port) --> 8080
Binary Serialization
local function pack(...)
local args = {...}
local data = {}
for _, v in ipairs(args) do
if type(v) == "number" then
data[#data + 1] = string.pack("I4", v)
elseif type(v) == "string" then
data[#data + 1] = string.pack("I4", #v) .. v
end
end
return table.concat(data)
end
local function unpack(data)
local pos = 1
local results = {}
while pos <= #data do
local len = string.unpack("I4", data, pos)
pos = pos + 4
local str = string.unpack("c" .. len, data, pos)
pos = pos + len
results[#results + 1] = str
end
return table.unpack(results)
end
Common Mistakes
1. Serializing circular references
Simple serialization loops infinitely on circular references. Track visited tables to detect cycles.
2. Security issues with load/dofile
Never load data from untrusted sources. load executes arbitrary Lua code. Use sandbox or JSON for untrusted data.
3. Not handling edge cases
nil values, NaN, infinite, metatables, and userdata all need special handling in serialization.
Practice Questions
1. How do you serialize a table to a file?
Write Lua code that reconstructs the table: f:write("return " .. serialize(table)). Load with dofile.
2. What is the security risk of dofile? dofile executes arbitrary Lua code. A malicious file can run system commands or delete files.
3. How do you handle circular references in serialization? Track already-serialized tables with a table mapping references to placeholder names.
FAQ
{{< faq question="Is there a standard serialization format in Lua?" >}} No built-in format. Common choices: Lua tables (fast, but unsafe for untrusted data), JSON (via libraries), or binary formats. {{< /faq >}}
{{< faq question="How do I serialize metatables?" >}} Store __metatable entries. Standard serialization ignores metatables. Customize your serializer to include them. {{< /faq >}}
{{< faq question="What is faster: string serialization or binary?" >}} Binary is faster to parse and smaller. Lua table serialization is simpler to debug but slower for large datasets. {{< /faq >}}
What's Next
Now learn about UTF-8 support in Lua.
| Topic | Description | Link |
|---|---|---|
| UTF-8 | Unicode handling | {{< ref "29-utf8" >}} |
| Goto and Labels | Advanced flow control | {{< ref "30-goto-labels" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro