Save Table To File |
|
Characteristics:
Files:wiki_insecure/users/chill/table.save-1.0.lua
NOTICE: NOT suitable for huge tables. Saving a table containing 100.000 subtables with 25 (1 short text line and 24 numerical entries) fields works. Somewhere above that performance is disastrous when saving. And you get an "constant table overflow" error when you try to read it back. With smaller tables it seems to work. Especially considering it is a cut and past solution to your need. There is some test code that shows that you can very well save such big tables, of course this is also a machine issue.
--[[ Save Table to File Load Table from File v 1.0 Lua 5.2 compatible Only Saves Tables, Numbers and Strings Insides Table References are saved Does not save Userdata, Metatables, Functions and indices of these ---------------------------------------------------- table.save( table , filename ) on failure: returns an error msg ---------------------------------------------------- table.load( filename or stringtable ) Loads a table that has been saved via the table.save function on success: returns a previously saved table on failure: returns as second argument an error msg ---------------------------------------------------- Licensed under the same terms as Lua itself. ]]-- do -- declare local variables --// exportstring( string ) --// returns a "Lua" portable version of the string local function exportstring( s ) return string.format("%q", s) end --// The Save Function function table.save( tbl,filename ) local charS,charE = " ","\n" local file,err = io.open( filename, "wb" ) if err then return err end -- initiate variables for save procedure local tables,lookup = { tbl },{ [tbl] = 1 } file:write( "return {"..charE ) for idx,t in ipairs( tables ) do file:write( "-- Table: {"..idx.."}"..charE ) file:write( "{"..charE ) local thandled = {} for i,v in ipairs( t ) do thandled[i] = true local stype = type( v ) -- only handle value if stype == "table" then if not lookup[v] then table.insert( tables, v ) lookup[v] = #tables end file:write( charS.."{"..lookup[v].."},"..charE ) elseif stype == "string" then file:write( charS..exportstring( v )..","..charE ) elseif stype == "number" then file:write( charS..tostring( v )..","..charE ) end end for i,v in pairs( t ) do -- escape handled values if (not thandled[i]) then local str = "" local stype = type( i ) -- handle index if stype == "table" then if not lookup[i] then table.insert( tables,i ) lookup[i] = #tables end str = charS.."[{"..lookup[i].."}]=" elseif stype == "string" then str = charS.."["..exportstring( i ).."]=" elseif stype == "number" then str = charS.."["..tostring( i ).."]=" end if str ~= "" then stype = type( v ) -- handle value if stype == "table" then if not lookup[v] then table.insert( tables,v ) lookup[v] = #tables end file:write( str.."{"..lookup[v].."},"..charE ) elseif stype == "string" then file:write( str..exportstring( v )..","..charE ) elseif stype == "number" then file:write( str..tostring( v )..","..charE ) end end end end file:write( "},"..charE ) end file:write( "}" ) file:close() end --// The Load Function function table.load( sfile ) local ftables,err = loadfile( sfile ) if err then return _,err end local tables = ftables() for idx = 1,#tables do local tolinki = {} for i,v in pairs( tables[idx] ) do if type( v ) == "table" then tables[idx][i] = tables[v[1]] end if type( i ) == "table" and tables[i[1]] then table.insert( tolinki,{ i,tables[i[1]] } ) end end -- link indices for _,v in ipairs( tolinki ) do tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil end end return tables[1] end -- close do end -- ChillCode
dofile( "table.save-1.0.lua" ) function Main() print( "Serialise Test ..." ) local t = {} t.a = 1 t.b = 2 t.c = {} -- self reference t.c.a = t t.inass = { 1,2,3,4,5,6,7,8,9,10 } t.inasst = { {1},{2},{3},{4},{5},{6},{7},{8},{9},{10} } -- random t.f = { [{ a = 5, b = 7, }] = "helloooooooo", [{ 1,2,3, m = 5, 5,6,7 }] = "A Table", } t.func = function(x,y) print( "Hello\nWorld" ) local sum = x+y return sum end -- get test string, not string.char(26) local str = "" for i = 0, 255 do str = str..string.char( i ) end t.lstri = { [str] = 1 } t.lstrv = str local function test() print("Hello") end t[test] = 1 print( "\n## BEFORE SAVE ##" ) printtbl( t ) --// test save to file assert( table.save( t, "test_tbl.lua" ) == nil ) -- load table from file local t2,err = table.load( "test_tbl.lua" ) assert( err == nil ) print( "\n## AFTER SAVE ##" ) print( "\n## LOAD FROM FILE ##" ) printtbl( t2 ) print( "\n//Test References" ) assert( t2.c.a == t2 ) print( "\n//Test Long string" ) assert( t.lstrv == t2.lstrv ) print( "\n//Test Function\n\n" ) assert( t2.func == nil ) print( "\n*** Test SUCCESSFUL ***" ) end function printtbl( t,tab,lookup ) local lookup = lookup or { [t] = 1 } local tab = tab or "" for i,v in pairs( t ) do print( tab..tostring(i), v ) if type(i) == "table" and not lookup[i] then lookup[i] = 1 print( tab.."Table: i" ) printtbl( i,tab.."\t",lookup ) end if type(v) == "table" and not lookup[v] then lookup[v] = 1 print( tab.."Table: v" ) printtbl( v,tab.."\t",lookup ) end end end function SaveHugeTable() local _t = {} for i=1,1000000 do local __t = {} table.insert(_t, __t) table.insert(__t, "THIS IS A STRING WITH A FEW CHARS") for i=1,30 do table.insert(__t, i) end end print("Built Hunge Table!") t1 = os.clock() assert( table.save( _t, "test_huge_tbl.lua" ) == nil ) print("Done Saving: "..os.difftime(os.clock(), t1)) _t = nil collectgarbage() t1 = os.clock() local t2,err = table.load( "test_huge_tbl.lua" ) print("Done Loading: "..os.difftime(os.clock(), t1)) print("Num: "..#t2) assert( err == nil ) print( "\n*** Test SUCCESSFUL ***" ) io.read() end Main() --SaveHugeTable() io.read()