Save Table To File

lua-users home
wiki

Save a Table to file; Load a Table from 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

Testcode
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()

See Also


RecentChanges · preferences
edit · history
Last edited August 7, 2013 2:19 am GMT (diff)