Hi, I’m trying to create a file that I can read and write to on Android from within the app. I’d like to be able to save a number into a txt file for a high-score and then load it upon successive access of the game. I am currently getting a runtime error that I am trying to create the file in a read-only file system. I found one mention of this issue on this forum but the question is from 2012. Writing on a text file
Does anyone know if there is a way to do this now?
There is a library called preference
that you can read/write simple values. I prefer using that. (Here)
I see they haven’t been updated for some time but @Glitch_Games GitHub has GGData.
You may also find useful stuff on @XeduR 's GitHub.
There’s a guide on how to do this on the docs at:
bgmadclown is right that I have useful stuff on this front, but my loadsave module is located in a different location.
It that handles loading and saving data while also providing backup saves, data validation and data encoding. The data encoding is just there to make the data a bit more difficult to be read by the end-user and the data validation will prevent unwanted tampering of the save files.
I still haven’t added public documentation for the module/plugin, but its functions are:
loadsave.debugMode( boolean )
- enables debug prints (defaults to false)
loadsave.protectData( boolean )
- toggles data validation and encoding on/off (defaults to true)
loadsave.setPepper( string )
- change the file’s pepper value
loadsave.save( data, filename, salt, [directory] )
- data to save, filename to save it under, as well as what salt to user when creating the hash (can be really anything, including an empty string). The directory is optional (defaults to documents)
loadsave.load( filename, salt, [directory] )
- file to load, the same salt that was used to save the file, and the optional directory where the file is stored in (defaults to documents)
We’ve moved our Glitch stuff away from my GG libs and towards my Scrappy libs instead.
Such as Scrappy Data and Scrappy Settings.
@XeduR My concern with that is being able to overwrite data constantly. Do I have to use JSON to do that? Why can’t I just create a text file in system.DocumentsDirectory with io.open(‘w’) and update it as I go?
Depends on what you mean by constantly. If it’s after user has updated their preferences, started or finished a level, then there’s absolutely no problem.
My module, or the one detailed in docs, both use JSON for it because it makes saving and loading data to and from Lua tables very easy. My module does also support just saving regular strings too.
If you don’t wish to use JSON, then you’d need to find some other means of saving data from Lua tables to a file or for getting the save data from the file back into useable form in Lua.
@XeduR To clarify I am talking about a trivia-style game where it would update every time a new high score is achieved with a
if newvalue > oldvalue then
newvalue = highscore
kind of comparison. Basically, I want to save a value between sessions but I keep getting stuck on the read-only system error I mentioned. Can you think of any way to do this with Lua without JSON?
@bgmadclown OK, I’m doing basically the same thing here that you are doing in preference.
local function saveFile( fileName, fileData )
--Path for file
local path = system.pathForFile( fileName, system.DocumentsDirectory )
local file = io.open( path, "w" )
if file then
file:write( fileData )
io.close( file )
end
end
local function loadFile( fileName )
local path = system.pathForFile( fileName, system.DocumentsDirectory )
local file = io.open( path, "r" )
if file then
local fileData = file:read( "*a" )
io.close( file )
return fileData
else
return false
end
end
on the saveFile function, is the fileData part required?
When my app starts, I’m trying to create the file and its giving me a runtime error that I’m in a read-only file system. Here’s what I’ve got to create the file where I’m encountering the main issue:
lfs = require( "lfs" )
path = system.pathForFile( "high_score.txt", system.DocumentsDirectory )
file2,err = assert(io.open( "high_score.txt", 'a' ))
if file2 then
file2:write( )
file2:close()
else
print("error" .. err)
end
Let’s put it like this, there is no reason why I wouldn’t use JSON for this. In fact, I’d just use my aforementioned module, or just copy the implementation from the documentation.
Seems to me like you’re trying to do a lot of unnecessary work for no reason. Why don’t you want to use JSON?
Preference is not my library. I got it back in the day and still use it.
The reason for your code to silently fail is that you are not using path
in io.open
. You should change
file2,err = assert(io.open( "high_score.txt", 'a' ))
with
file2,err = assert(io.open( path, 'a' ))
and it should work.
Adding to XeduR, if you are going to make something more than that in the future, you may want to use formatted files to keep track of things. Reading/Writing and Viewing those files would be far easier than writing everything to plain text files. Anyway, it’s your choice in the end.
Also, if you are trying to get a grip on the API it’s good to try and write your own code for some of the stuff. Even in that case, I’d suggest inspecting the source of those libraries instead. That’d save a lot of time.
I’ve never used JSON and it seems like a lot of extra work to save/overwrite a single value. Also, I just really want to get this project to phase1 completion before I start adding features and making improvements to the code.
And I don’t know how to load your module. I’m guessing its something like
require("loadsave.lua")
loadsave.save( data, filename, salt, [directory] )
but I just want to get this on paper as I intended and then later I’ll go back and make stuff “good”.
For more information on including external modules:
OK, perfect. That fixed the issue I was having. Can you point me to some documentation that explains why I need to use path instead of the file name for that? And additionally, why it would error on the document name but not the path?
And thank you for the documentation on APIs!
Well, because that’s how it works, how it was implemented. Here’s the syntax:
bgmadclown already helped you out with most of the stuff, but there’s no need to worry about using JSON in Solar2D. In fact, it’s better to get started with doing things “the better way” right away.
For instance,
local json = require( "json" )
local myData = {}
myData.highscore = 123456
myData.name = "Player"
myData.someTable = {}
local serializedJSON = json.encode( myData )
print( serializedJSON ) -- {"highscore":123456,"name":"Player","someTable":[]}
When you’re later reading the file, you can use json.decode
to turn the JSON formatted string back into a Lua table.
If you’re using JSON, then the only extra steps you need to do with saving and loading the data is to 1) require JSON, and use json.encode
or json.decode
when saving/loading. Now, if you later need to add some more information into the save file, like user preferences, then you can just add them to the table and save it.