just some stuff i've learned since july... :) i hope
someone can learn from this.
dl the entire how-to HERE (http://www.stcycles.com/hate/scripts/save_load_data_howto.lua)(updated with all posts)
--////////////////////////////////////////////////////////
--//Everything you need to:
--// save strings and tables
--// load strings and tables
--// verify/make files and paths
--//-------------------------
--///by ?ottledHat?\\\
--// resources:
--// [URL]http://www.lua.org/manual/4.0/manual.html#6.4[/URL]
--// [URL]http://www.lua.org/manual/5.0/manual.html#5.6[/URL]
--//-------------------------
--// paths may be absolute: "c:\\path\\to\\a dir\\file.txt"
--// relative to current dir: "scripts/save data/savefile.txt"
--// UNC(network) paths use "\\\\pcname\\share\\this folder\\file.txt" --only if proper rights exist.. ;)
--//-------------------------
--//-------------------------
--//VERIFY FILE (make)
--//-------------------------
--///verifyFile()\\\
--// make file and path(s)
--// can used to verify a save/load file at start to prevent read/write errors
--// when the verify funtion is used no changes are made to the file if it exists. a blank file with no data is created otherwise.
--// optional returns: 1 file exists.. 2 on success new file made returns.. 0 on fail
--// ...fails if path/filename is invalid to winblows.
--// strip the function, put in main or at top of script to verify/make your global file at start.
--//LUA5 / BCDC / DCDM
function verifyFile(file) --//(make file)
local f,e = io.open(file, "a+" )
if f then f:close() return 1
else
local _,_,path = string.find(file, "(.+[/_\\]).+$")
if path ~= nil then os.execute("mkdir ".."\""..gsub(path, "/", "\\").."\"") end
f,e = io.open( file, "a+" )
if f then f:close() return 2
else return 0 end
end
end
--//LUA4 / PTOKAX
function verifyFile(file)--//(make file)
local f,e = openfile( file, "a+" )
if f then closefile(f) return 1
else
local _,_,path = strfind(file, "(.+[/_\\]).+$")
if path ~= nil then execute("mkdir ".."\""..gsub(path, "/", "\\").."\"") end
f,e = openfile( file, "a+" )
if f then closefile(f) return 2
else return 0 end
end
end
--//verifFile() EXAMPLE.
MySaveFile = "scripts/data/thisbot/settings.txt"
x = verfyFile(MySaveFile)
if x = 0 then
--fail..path/filename is invalid to winblows
elseif x = 1
--file exists.
elseif x = 2
--file or path did not exist.. now they do.
end
--//-------------------------
--//SAVE DATA .. (strings)
--//-------------------------
--///saveData()\\\
--// used to save a string to a file.
--// will make file and path if they don't exist.
--// optional returns: 1 data saved.. 2 data saved to new file.. returns.. 0 on fail
--// ...fails if path/filename is invalid to winblows, or file locked to other process.
--//LUA5 / BCDC / DCDM
function saveData(file,string)
local f,e = io.open(file, "a+" ) --// [URL]http://www.lua.org/manual/5.0/manual.html#5.6[/URL] <--more output options/ "a+" appends
if f then
f:write(string)
f:close()
return 1
else
local _,_,path = string.find(crazyFileName, "(.+[/_\\]).+$")
if path ~= nil then os.execute("mkdir ".."\""..gsub(path, "/", "\\").."\"") end
f,e = io.open( file, "a+" )
if f then
f:write(string)
f:close()
return 1
else
--**yourGlobalFileName** = "_DefaultFileName"--//EDIT to your global and default filenames.(no path!)
--saveData(**yourGlobalFileName**, string) --//for if you use the default filename...
return 0
end
end
end
--//LUA4 / PTOKAX
function saveData(file, string)
local f,e = openfile( file, "a+" )--// [URL]http://www.lua.org/manual/4.0/manual.html#6.4[/URL] <--more output options/ "a+" appends
if f then
write(f,string)
closefile(f)
return 1
else
local _,_,path = strfind(sFileName, "(.+[/_\\]).+$")
if path ~= nil then execute("mkdir ".."\""..gsub(path, "/", "\\").."\"") end
f,e = openfile( sFileName, "a+" )
if f then
write(f,string)
closefile(f)
return 2
else
--**yourGlobalFileName** = "_DefaultFileName"--//EDIT to your global and default filenames.(no path!)
--saveData(**yourGlobalFileName**, string) --//for if you use the default filename...
return 0
end
end
end
--//saveData() EXAMPLE.
MySaveFile = "scripts/data/thisbot/settings.txt"
MySaveData = "bleh blah bluh"
x = saveData(MySaveFile, MySaveData)
if x = 0 then
--fail..path/filename is invalid to winblows
elseif x = 1
--file exists. data saved... (in this case "a+" appends)
elseif x = 2
--file or path did not exist.. now they do. data saved
end
--//-------------------------
--//SERIALIZE TABLES
--//-------------------------
--///Serialize()\\\
--// used to convert a table into a string for saving. this allows for quick easy reading back in.
--// tTable = the table you want to save. sTableName = the tables name as a string. sTab = leave blank or "".
--//LUA5 / BCDC / DCDM
function Serialize(tTable, sTableName, sTab)
sTab = sTab or "";
sTmp = ""
sTmp = sTmp..sTab..sTableName.."={"
local tStart = 0
for key, value in tTable do
if tStart == 1 then
sTmp = sTmp..",\r\n"
else
sTmp = sTmp.."\r\n"
tStart = 1
end
local sKey = (type(key) == "string") and string.format("[%q]",key) or string.format("[%d]",key);
if(type(value) == "table") then
sTmp = sTmp..SerializeCrazy(value, sKey, sTab.."\t");
else
local sValue = (type(value) == "string") and string.format("%q",value) or tostring(value);
sTmp = sTmp..sTab.."\t"..sKey.." = "..sValue
end
end
sTmp = sTmp.."\r\n"..sTab.."}"
return sTmp
end
--//LUA 4 / PTOKAX
function Serialize(tTable, sTableName, sTab)
sTab = sTab or "";
sTmp = ""
sTmp = sTmp..sTab..sTableName.."={"
local tStart = 0
for key, value in tTable do
if tStart == 1 then
sTmp = sTmp..",\r\n"
else
sTmp = sTmp.."\r\n"
tStart = 1
end
local sKey = (type(key) == "string") and format("[%q]",key) or format("[%d]",key);
if(type(value) == "table") then
sTmp = sTmp..Serialize(value, sKey, sTab.."\t");
else
local sValue = (type(value) == "string") and format("%q",value) or tostring(value);
sTmp = sTmp..sTab.."\t"..sKey.." = "..sValue
end
end
sTmp = sTmp.."\r\n"..sTab.."}"
return sTmp
end
--//Serialize() EXAMPLE.
--// this example will cover converting the table with Serialize, saveing with saveData, then loading with dofile.
MyTable = {["bleh"] = 1, ["bloop"] = {["bloop1"] = "bleeeep1", ["bloop2"] = "bleeeep2"}}
MySaveFile = "scripts/data/thisbot/settings.txt"
MySaveData = Serialize(MyTable, "MyTable", "") -- the second argument determines the name of the table when read back in.
x = saveData(MySaveFile, MySaveData)
if x = 0 then
--fail..path/filename is invalid to winblows
elseif x = 1
--file exists. data saved... (in this case "a+" appends)
elseif x = 2
--file or path did not exist.. now they do. data saved
end
--//ok, so the file is all saved now.. and the script is restarting due to whatever reason..
--to load the table back into the script...
x = verifyFile(MySaveFile)
if x = 0 then
--fail..path/filename is invalid to winblows
elseif x = 1
dofile(MySaveFile) --loads the table into the scipt, with the name being the second argument passed to serialize.. in this case "MyTable" (no change)
--file exists.
elseif x = 2
--file or path did not exist.. now they do.
--//rebuild your blank tables static values!
end
--// so why verify then dofile?
--// because if the file did not exist. then there is no tabel data. and if you have static vaules in the table..
--// when your script tries to access them it will error out. so you would wnat to built the blank table there.
--// think of it as first run and someone new is using your script, so they don't have save data file yet...
--// meaning there is nothing to load in...
--//-------------------------
--//Load TABLES (that were serialized)
--//-------------------------
--// loading tables that were serialized is the quickest and easiest way to load saved data. (that i have found)
--// the only thing needed is dofile.
--// i usually verify the file before doing the dofile to make sure there are no errors.
--//LUA 4 / LUA 5
dofile("yourfilename")
--//dofile() EXAMPLE.
--see example for Serialize for dofile.
--//This is the end... for now... i hope you were able
--// to learn something from this file. more file manipulation
--// to come! requests welcomed.
--///BH\\\
--////////////////////////////////////////////////////////
:D
-BH
a couple random ones..
--//Remove a line number from a file.
--// with a lil moding this function can easily, add data before/after/on a line number.. read line number, and more.
--// LUA 5
function removeLine(file,rline)
local lineN = 1
local tmp =""
for line in io.lines(filename) do
if lineN ~= rline then
tmp = tmp..line.."\r\n"
end
lineN = lineN +1
end
local f,e = io.open( filename, "w+" ) --// [URL]http://www.lua.org/manual/5.0/manual.html#5.6[/URL] <--more output options/ "w+" overwrites.
if f then
f:write( tmp )
f:close()
end
end
--//LUA 4
function removeLine(file,rline)
local lineN,tmp = 1, ""
readfrom(file)
while 1 do
local line = read()
if line == nil then break
else
if lineN ~= rline then tmp = tmp..line.."\n" end
lineN = lineN + 1
end
end
readfrom()
local f,e = openfile(file, "w+" ) --//... "w+" overwrites
if f then
write(f,tmp)
closefile(f)
end
end
--//load DC++ favorite users into talble (LUA5 BCDC / DCDM only)
--// easily modded to do other things.
--// returns a table in the format {["nick1"] = 1, ["nick2"] = 1, ["nick3"] = 1, ... } ...so the names are hashed
function loadFavUsers()
local start=0
local favUsers={}
for line in io.lines("Favorites.xml") do
if string.find(line, "") then
return favUsers
break
end
if start ==1 then
local s,e,favnick = string.find(line, " favUsers[favnick] = 1
end
if string.find(line, "") then
start=1
end
end
-BH
Nice going, some interesting parts.
Keep it coming / NightLitch
somehow i forgot to add this one:
--//-------------------------
--//LOAD DATA .. (strings)
--//-------------------------
--///loadData()\\\
--// used to load an entire file to a string.
--// returns files text as string, or nil on fail
--//LUA5 / BCDC / DCDM
function loadData(file)
local tmp = ""
local f,e = io.open(file,"r")
if f then
tmp = f:read("*a")
f:close(f)
return tmp
else return nil end
end
--//LUA4 / PTOKAX
function loadData(file)
local tmp = ""
local f,e = openfile(file,"r")
if f then
tmp = read(f,"*a")
closefile(f)
return tmp
else return nil end
end
--//loadData() EXAMPLE.
MySaveFile = "scripts/data/thisbot/settings.txt"
MySavedData = loadData(MySaveFile)
dl the entire file w/ all the functions here (http://www.stcycles.com/hate/scripts/save_load_data_howto.lua) .
-BH
One thing I thought might be useful is for saving/loading simple arrays, for when you don't need data associated with them, or don't care what numbers are associated with them either.
I keep a list of everyone who has read the rules in an array, using table.insert (and table.remove when they break a rule after reading them, so they must re-read the rules to be re-added) for updating, and save it like this:
function OnExit()
io.output("readrules.lay")
local s = ((table.getn(readrules) ~= 0) and "\""..table.concat(readrules,"\",\"").."\"" or "")
io.write("readrules = {"..s.."}")
io.output()
end
then for loading it:
function Main()
local afile = "readrules.lay"
local handle = io.open(afile,"r")
if handle then
handle:close()
dofile(afile)
os.remove(afile)
else
readrules = {}
end
end
I haven't tried turning it into generic loadarray() savearray() functions, so you're welcome to yourself.