Jump to content




Saving multiple tables and loading them from a file


9 replies to this topic

#1 The Higher Realm

  • Members
  • 23 posts
  • LocationUSA

Posted 12 March 2017 - 01:59 AM

I feel like this should be simple, but I am struggling with it.
I can store a single table in a file with textutils and take it out but how would I go about storing multiple and be able to load one with a value from it and store into a variable.

So the file would contain something like this

{
  username="actiquack",
  password="secret password",
}
{
  username="dan",
  password="computercraft",
}

and I could grab the table with just a value like

function getTable(item, value)
  table = get entire table that has item == value
  table = textutils.unserialise(table)
  return table
end

data = getTable("username", "dan")

Then as an end result I would have a table that has the values so I could do data.password to get "computercraft"

Edited by Actiquack322, 12 March 2017 - 02:00 AM.


#2 valithor

  • Members
  • 1,053 posts

Posted 12 March 2017 - 02:20 AM

You could do something like this, assuming all of the tables written to the file are written using writeLine instead of just write:

local h = fs.open(file,"r") --# getting the information from the file that contains the tables
local str = h.readAll()
h.close()

local function unserializeTables()
  local returns = {} --# table to hold all the tables that will be returned
  local tbl --# creating a local variable named tbl
  while #str > 0 do
	tbl,str = str:match("^(.-\n}\n)(.*)") --# will explain below
	table.insert(returns,textutils.unserialize(tbl)) --# inserting the unserialized table into the returns table
  end
  return unpack(returns) --# returns the unserialized tables in order from the first found in the file
end

"^(.-\n}\n)(.*)"
-- This is a lua pattern, which essentially looks for a closing curly brace "}" that is surrounded on both sides by a end line character \n. This only occurs at the last curly brace of a table, so you could unserialize nested tables using this.

A easier way to do this might be just to put all your tables into a single table before serializing it, say you wanted to save tables named tbl1, tbl2, and tbl3 to a file:

local saveTable = {tbl1,tbl2,tbl3}

local h = fs.open("saveFile","w")
h.write(textutils.serialize(saveTable))
h.close()

To read this file:
local h = fs.open("saveFile","r")
local tbl = textutils.unserialize(h.readAll())
h.close()

tbl1,tbl2,tbl3 = unpack(tbl)

Edited by valithor, 12 March 2017 - 02:29 AM.


#3 The Higher Realm

  • Members
  • 23 posts
  • LocationUSA

Posted 12 March 2017 - 03:07 AM

View Postvalithor, on 12 March 2017 - 02:20 AM, said:

local h = fs.open(file,"r") --# getting the information from the file that contains the tables
local str = h.readAll()
h.close()

local function unserializeTables()
  local returns = {} --# table to hold all the tables that will be returned
  local tbl --# creating a local variable named tbl
  while #str > 0 do
	tbl,str = str:match("^(.-\n}\n)(.*)") --# will explain below
	table.insert(returns,textutils.unserialize(tbl)) --# inserting the unserialized table into the returns table
  end
  return unpack(returns) --# returns the unserialized tables in order from the first found in the file
end

textutils errors with: "textutils:300: attempt to concatenate string and nil"
tb1 variable doesn't get anything stored in it.

#4 valithor

  • Members
  • 1,053 posts

Posted 12 March 2017 - 03:12 AM

View PostActiquack322, on 12 March 2017 - 03:07 AM, said:

View Postvalithor, on 12 March 2017 - 02:20 AM, said:

local h = fs.open(file,"r") --# getting the information from the file that contains the tables
local str = h.readAll()
h.close()

local function unserializeTables()
  local returns = {} --# table to hold all the tables that will be returned
  local tbl --# creating a local variable named tbl
  while #str > 0 do
	tbl,str = str:match("^(.-\n}\n)(.*)") --# will explain below
	table.insert(returns,textutils.unserialize(tbl)) --# inserting the unserialized table into the returns table
  end
  return unpack(returns) --# returns the unserialized tables in order from the first found in the file
end

textutils errors with: "textutils:300: attempt to concatenate string and nil"
tb1 variable doesn't get anything stored in it.

It works in my tests, make sure you are saving the tables to the file using writeLine instead of just write as I stated above the code.

edit:

writeLine puts endline characters after everything that is written, which is what the pattern is looking for.

Edited by valithor, 12 March 2017 - 03:13 AM.


#5 The Higher Realm

  • Members
  • 23 posts
  • LocationUSA

Posted 12 March 2017 - 03:21 AM

View Postvalithor, on 12 March 2017 - 03:12 AM, said:

View PostActiquack322, on 12 March 2017 - 03:07 AM, said:

View Postvalithor, on 12 March 2017 - 02:20 AM, said:

local h = fs.open(file,"r") --# getting the information from the file that contains the tables
local str = h.readAll()
h.close()

local function unserializeTables()
  local returns = {} --# table to hold all the tables that will be returned
  local tbl --# creating a local variable named tbl
  while #str > 0 do
	tbl,str = str:match("^(.-\n}\n)(.*)") --# will explain below
	table.insert(returns,textutils.unserialize(tbl)) --# inserting the unserialized table into the returns table
  end
  return unpack(returns) --# returns the unserialized tables in order from the first found in the file
end

textutils errors with: "textutils:300: attempt to concatenate string and nil"
tb1 variable doesn't get anything stored in it.

It works in my tests, make sure you are saving the tables to the file using writeLine instead of just write as I stated above the code.

edit:

writeLine puts endline characters after everything that is written, which is what the pattern is looking for.

I am my file looks like
{
  username="actiquack",
  pass="word",
}
{
  username="testname",
  pass="testpass",
}
I serialize the table and do h.writeLine(table)

Edited by Actiquack322, 12 March 2017 - 03:22 AM.


#6 valithor

  • Members
  • 1,053 posts

Posted 12 March 2017 - 03:29 AM

I have no idea why it is not working. I recreated the file using writeLine, and it worked as intended. It might just be easier to use the second solution.

#7 The Higher Realm

  • Members
  • 23 posts
  • LocationUSA

Posted 12 March 2017 - 04:36 AM

View Postvalithor, on 12 March 2017 - 03:29 AM, said:

I have no idea why it is not working. I recreated the file using writeLine, and it worked as intended. It might just be easier to use the second solution.

Alright I'm using the second option and I got it to work sorta. I'm trying to store usernames and passwords. You have a line like tb1, tb2, tb3 = uppack(tbl). How would I do that with any amount of tables and then be able to read through those and find the one with the matching username and password?

#8 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 12 March 2017 - 04:41 AM

I suggest a different table structure entirely:

{
	["user1"] = "password1",
	["user2"] = "password2",
	-- etc
}

A login check would look something like:

if users[userTryingToLogin] == read("*") then

If you wanted to store additional details for each user, you might do:

{
	["user1"] = {
			["password"] = "password1",
			["favouriteColour"] = colours.green,
			-- etc
		},
	
	["user2"] = {
			["password"] = "password2",
			["favouriteColour"] = colours.blue,
			-- etc
		},
	
	-- etc
}

A login check would look something like:

if users[userTryingToLogin].password == read("*") then


#9 The Higher Realm

  • Members
  • 23 posts
  • LocationUSA

Posted 12 March 2017 - 05:22 AM

View PostBomb Bloke, on 12 March 2017 - 04:41 AM, said:

{
	["user1"] = {
			["password"] = "password1",
			["favouriteColour"] = colours.green,
			-- etc
		},
	
	["user2"] = {
			["password"] = "password2",
			["favouriteColour"] = colours.blue,
			-- etc
		},
	
	-- etc
}

This works better, but how do I write another table to the file?

Edited by Actiquack322, 12 March 2017 - 05:50 AM.


#10 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 12 March 2017 - 08:34 AM

Create one "master" table, stick your other tables into that, then serialise and write it to disk all in one go.

If you're having trouble seeing how that might work, give some examples of how you want the data to be organised when it's not in the file, but rather when it's loaded into RAM for your script to use.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users