This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Bab's profile picture

"human-readable" textutils.serialize not easy to unserialize

Started by Bab, 01 January 2015 - 07:19 PM
Bab #1
Posted 01 January 2015 - 08:19 PM
I've been away from the forums and CC for a while, but back when I used it textutils used the old format, which meant you could serialize a table to a file and later just read the single line and unserialize it. However, this doesn't work anymore due to the new human-readable format which makes the previously one line table take up multiple lines. How would I easily go about reading a table from a file full of other variables?
wieselkatze #2
Posted 01 January 2015 - 09:11 PM
That's as easy as using readLine().
If you look here you see that there is a f.readAll(). This reads the whole file and concatenates all lines together with \n as the separator.

You could just use this:


local f = fs.open( yourfile, "r" )
local content = textutils.unserialize( f.readAll() )
f.close()

an content would be your unserialized table.
Bab #3
Posted 01 January 2015 - 09:50 PM
The problem with that, however is that beside that table I also have other variables saved in the file. So beside a positional table I also have variables for the amount of blocks mined, in the same file. This was very convenient with the old textutils.
wieselkatze #4
Posted 01 January 2015 - 09:58 PM
How exactly does your file look like? As textutils.unserialize() only uses loadstring(), you could actually pretty easily write your own function for loading all the variables and then accessing them via creating an own environment for them - kinda like os.loadAPI().
Bab #5
Posted 01 January 2015 - 10:08 PM
In this case, the file is

-1082.0
49.0
1601.0
20.0
1000.0
20.0
{
  dir = 1,
  z = 1601,
  y = 50,
  x = -1082,
}
{
  dir = 2,
  z = 1601
  y = 50,
  x= -1082,
}
wieselkatze #6
Posted 01 January 2015 - 10:35 PM
Okay, if you wrote the variable names in front of the values, you could definitely use loadstring().
Like this:

a = -1082.0
b = 49.0
...

You could then make a function like this:

local function loadFile( path )
  if fs.exists( path ) then
	local f = fs.open( path, "r" )
	  if f then
		local content, env = f.readAll(), {}
		local func, err = loadstring( content )
		
		if err then
		  error( err )
		end
		
		setfenv( func, env )
		func()
		
		return env
	  end
  end
end

This would be a 'smaller' version of os.loadAPI. As the global functions are not needed there is no need for setting _G as __index in env's metatable. Also there is nor checking if the API is actually loaded - we wouldn't have to do that as this isn't an API anyway.

You could then use the function to get a table with all the variables you need and use them like this:

local a = loadFile( "yourpath/something" )
print( a.a ) --# Or whatever you named your variable

EDIT: The indendation got somewhat messy, meh.
Edited on 01 January 2015 - 09:38 PM
Bab #7
Posted 01 January 2015 - 10:48 PM
It's not so much that I don't know how to get it working, it's just a lot more effort for something that used to be simple and intuitive. I save the file with f.writeLine(textutils.serialize(variable)) and read it with textutils.unserialize(f.readLine()), but now I need to save the parts individually, or do something like you did which is a really roundabout way for it.
MKlegoman357 #8
Posted 01 January 2015 - 11:13 PM

local oneLineSerializedTable = textutils.serialize({test = 1}):gsub("\n", "")
Bab #9
Posted 01 January 2015 - 11:33 PM
Now that's a nice, simple, hackish solution. Thanks, both of you!
Edited on 01 January 2015 - 10:34 PM
wieselkatze #10
Posted 02 January 2015 - 12:53 AM

local oneLineSerializedTable = textutils.serialize({test = 1}):gsub("\n", "")

Wow, didn't think of that :D/>