Serialization functions accept a config table. Currently only one configuration option is defined.
config = {
skip_empty_tables = false
-- used for write_to_fd/write_to_file
-- if true, does not store empty tables
-- On next read, keys that mapped to empty tables resolve to nil
}
If you want to use all-default config options, you can pass nil
as the config parameter.
All of these functions call error(<message>)
if an error occurs. Errors can be caught with pcall()
.
Writes the contents of root_table
to the file from the file handle given by file
, and closes the file descriptor afterwards.
First, opens filename
for write. Then, writes the contents of root_table
to the file.
Reads the file from the file handle given by file
, and closes the file descriptor afterwards. Returns the deserialized table.
First, opens filename
for read. Then, reads the file and returns the deserialized table.
serialize.lua can be loaded as a standard Lua module even outside Minetest, like this:
local serialize = require("serialize")
Serialize_lib wraps write_to_file and read_from_file into 2 functions that do not throw errors but instead log the fact to the server log and have an appropriate return value:
Serializes root_table
into filename
. On success, returns true. On failure, logs the error, then returns false and the error message.
Deserializes the given file. On success, returns the deserialized table. On failure, logs the error, then returns false and the error message.
serialize_lib provides functions for atomic saving. This means that if the process is interrupted during writing the save file, it is ensured that no save data gets corrupted and that instead the old state is read.
The atomic system is flexible, and can be used not only to save serialized Lua tables but arbitrary file formats by means of a callback function. This callback function gets passed a file descriptor to operate on.
The plain scheme just overwrites the file in place. This however poses problems when we are interrupted right within the write, so we have incomplete data. So, the following scheme is applied:
Unix:
filename.new
filename.new
to filename
, clobbering previous fileWindows:
filename.new
filename
filename.new
to filename
We count a new version of the state as "committed" after stage 2.
During loading, we apply the following order of precedence:
filename
filename.new
(windows only, in case we were interrupted just before 3. when saving)All of these functions return either true on success or nil, error on error.
Load a saved state.
If 'callback' is nil: reads serialized table. Returns the read table, or nil,err on error.
If 'callback' is a function (signature func(file_handle)
): Counterpart to save_atomic with function argument. Opens the file and calls callback on it. If the callback function throws an error, and strict loading is enabled, that error is propagated. The callback's first return value is returned by load_atomic.
Save a file atomically.
'data' is the data to be saved (when a callback is used, this can be nil)
If 'callback' is nil: 'data' must be a table, and is serialized into the file
If 'callback' is a function (signature func(data, file_handle)
): Opens the file and calls callback on it. The 'data' argument is the data passed to save_atomic(). If the callback function throws an error, and strict loading is enabled, that error is propagated. The callback's first return value is returned by load_atomic().
Important: the callback must close the file in all cases!
Saves multiple files synchronously. First writes all data to all filename
.new files, then moves all files in quick succession to avoid inconsistent backups. parts_table is a table where the keys are used as part of the filename and the values are the respective data written to it.
parts_table={foo={...}, bar={...}}
, then filename_prefix
foo and filename_prefix
bar are written out.If 'callbacks_table' is defined, it is consulted for callbacks the same way save_atomic does.
callbacks_table = {foo = func()...}
, then the callback is used during writing of file 'foo' (but not for 'bar')Important: the callback must close the file in all cases!