Save Table To File |
|
Since building a string from a big table, uses more time than saving the table to file and loading it from there, one should use table.save( table, true ) to get the stringtable from a big table
Characteristics:
Files:wiki_insecure/users/chill/table.save-0.94.lua
--[[ Save Table to File/Stringtable Load Table from File/Stringtable v 0.94 Lua 5.1 compatible Userdata and indices of these are not saved Functions are saved via string.dump, so make sure it has no upvalues References are saved ---------------------------------------------------- table.save( table [, filename] ) Saves a table so it can be called via the table.load function again table must a object of type 'table' filename is optional, and may be a string representing a filename or true/1 table.save( table ) on success: returns a string representing the table (stringtable) (uses a string as buffer, ideal for smaller tables) table.save( table, true or 1 ) on success: returns a string representing the table (stringtable) (uses io.tmpfile() as buffer, ideal for bigger tables) table.save( table, "filename" ) on success: returns 1 (saves the table to file "filename") on failure: returns as second argument 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 ---------------------------------------------------- chillcode, http://lua-users.org/wiki/SaveTableToFile 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 ) s = string.format( "%q",s ) -- to replace s = string.gsub( s,"\\\n","\\n" ) s = string.gsub( s,"\r","\\r" ) s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" ) return s end --// The Save Function function table.save( tbl,filename ) local charS,charE = " ","\n" local file,err -- create a pseudo file that writes to a string and return the string if not filename then file = { write = function( self,newstr ) self.str = self.str..newstr end, str = "" } charS,charE = "","" -- write table to tmpfile elseif filename == true or filename == 1 then charS,charE,file = "","",io.tmpfile() -- write table to file -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error else file,err = io.open( filename, "w" ) if err then return _,err end end -- initiate variables for save procedure local tables,lookup = { tbl },{ [tbl] = 1 } file:write( "return {"..charE ) for idx,t in ipairs( tables ) do if filename and filename ~= true and filename ~= 1 then file:write( "-- Table: {"..idx.."}"..charE ) end file:write( "{"..charE ) local thandled = {} for i,v in ipairs( t ) do thandled[i] = true -- escape functions and userdata if type( v ) ~= "userdata" then -- only handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables, v ) lookup[v] = #tables end file:write( charS.."{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( charS..value..","..charE ) end end end for i,v in pairs( t ) do -- escape functions and userdata if (not thandled[i]) and type( v ) ~= "userdata" then -- handle index if type( i ) == "table" then if not lookup[i] then table.insert( tables,i ) lookup[i] = #tables end file:write( charS.."[{"..lookup[i].."}]=" ) else local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i ) file:write( charS..index.."=" ) end -- handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables,v ) lookup[v] = #tables end file:write( "{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( value..","..charE ) end end end file:write( "},"..charE ) end file:write( "}" ) -- Return Values -- return stringtable from string if not filename then -- set marker for stringtable return file.str.."--|" -- return stringttable from file elseif filename == true or filename == 1 then file:seek ( "set" ) -- no need to close file, it gets closed and removed automatically -- set marker for stringtable return file:read( "*a" ).."--|" -- close file and return 1 else file:close() return 1 end end --// The Load Function function table.load( sfile ) -- catch marker for stringtable if string.sub( sfile,-3,-1 ) == "--|" then tables,err = loadstring( sfile ) else tables,err = loadfile( sfile ) end if err then return _,err end tables = tables() for idx = 1,#tables do local tolinkv,tolinki = {},{} for i,v in pairs( tables[idx] ) do if type( v ) == "table" and tables[v[1]] then table.insert( tolinkv,{ i,tables[v[1]] } ) end if type( i ) == "table" and tables[i[1]] then table.insert( tolinki,{ i,tables[i[1]] } ) end end -- link values, first due to possible changes of indices for _,v in ipairs( tolinkv ) do tables[idx][v[1]] = v[2] 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
function Main() dofile( "table.save-0.94.lua" ) print( "//Serialise Test ..." ) print( "//Building Table ..." ) 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.." "..i..": "..string.char( i ) str = str..string.char( i ) end t.lstri = { [str] = 1 } t.lstrv = str print( "\n## BEFORE SAVE ##" ) printtbl( t ) --// test save to file assert( table.save( t, "test.tbl" ) == 1 ) --// test save to string local strtbl = table.save( t ) --// test save to string over file local strtbl2 = table.save( t, true ) -- load table from file local t2 = table.load( "test.tbl" ) -- load table from string 1 local t3 = table.load( strtbl ) -- load table from string 2 local t4 = table.load( strtbl2 ) print( "\n## AFTER SAVE ##" ) print( "\n## LOAD FROM FILE ##" ) printtbl( t2 ) print( "\n## LOAD FROM STRING ##" ) --printtbl( t3 ) print( "\n## LOAD FROM STRING OVER FILE ##" ) --printtbl( t4 ) print( "\n//Test References" ) assert( t2.c.a == t2 ) assert( t3.c.a == t3 ) assert( t4.c.a == t4 ) print( "\n//Test Long string" ) assert( t.lstrv == t2.lstrv ) assert( t.lstrv == t3.lstrv ) assert( t.lstrv == t4.lstrv ) print( "\n//Test Function\n\n" ) assert( t2.func(2,2) == 4 ) assert( t3.func(2,3) == 5 ) assert( t4.func(2,3) == 5 ) print( "\n*** Test SUCSESSFULL ***" ) 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 Main()