What is the path to access data folders/files in the app’s Resource folder? I’m sure it must be very simple, but I couldn’t find it in the language help.
SpecialFolder.Resources
Thanks, Greg, for the quick response.
I’m still confused. I looked up SpecialFolder, and it says:
“Used to get a FolderItem for a specific folder or directory managed by the host operating system.”
I want to read and write to text files that are in sub-folders in the app’s Resources folder.
It appears that on Windows, the Resources folder is just in the same folder as the .exe app, but on a Mac it’s in the app’s Contents. Will the same code work for both systems?
…or am I trying to put my data files in the wrong place?
Maybe this can help:
https://documentation.xojo.com/api/files/specialfolder.html
If you need to write, then I think is better to use ApplicationData special folder.
That link is no help since it’s the page I just quoted from.
But isn’t ApplicationData in the system? I would like to include the data files are part of the app so it’s all in one place.
I want to read and write to text files that are in sub-folders in the app’s Resources folder.
It appears that on Windows, the Resources folder is just in the same folder as the .exe app, but on a Mac it’s in the app’s Contents. Will the same code work for both systems?
From what I read, you can’t write to text files in the Resource folder, at least on Mac. This has to do with security. You will need to copy/create the file you want to write to in another place, like ApplicationData special folder.
I think what happens is that files are put in the Resource folder, then your app can only read from those. If you need to write to app-specific files then your app needs to create a copy or new files in ApplicationData where you will be able to read/write.
I’m no expert but this is how I understand it works.
Thanks, Alberto. OK, that rules out using the Resources folder.
If I just put my data folders in the same folder as the app, then
f = GetFolderItem( “MyData” )
works fine on my systems (El Capitan and High Sierra) and on Windows to read and write to text files in the MyData folder, but on some other Macs it apparently can’t see the MyData folder. Can’t figure out why.
Each new version of macOS has tightened the security, there are things like translocation and sandboxing that protect the user (in theory) from bad code.
Things copied in the same folder than your app are not copied (translocated/sandboxed) with your app, that’s why your app on those systems can’t see the file next to your app because actually the macOS created a copy of your app elsewhere and did not copy your MyData.
Thanks again, Alberto, for clarifying this for me. Apparently this started with Catalina since my program was working on OS 10.14.
I tried putting my data files in ApplicationSupport, but my app had trouble finding them there, too.
I don’t suppose I could put a data folder in the app Contents so it would be copied along with the app? Or would I not be able to write there either?
You can put the data folder into app Contents and then you can copy it to ApplicationData where you can access it.
Im sure this conversation occurs on this forum and probably every other programming forum at least once per month.
Because of security on Mac and Windows:
You may not create files local to the app, or in the resources folder (which is local to the app), or in Program Files folder, or in Applications folder.
You just can’t.
Don’t waste your time trying,
We know that’s what you want to do, but you cannot.
Now: what you can do is create a folder in
Specialfolder.ApplicationData
SpecialFolder.SharedApplicationData
Specialfolder.Documents (expect Catalina to grumble , but it will allow you if the user allows you)
If your app ships with data that you want amendable, copy it there at first run.
Use the copy in future, not the file in your resources folder.
Well, at least I’m not alone with this problem. Xojo should put this info in the help for FolderItem.
Perhaps the only thing I like about Windows is that MS maintains backward compatibility while Apple repeatedly obsoletes things. I have SheepShaver on my main system to be able to run OS 9 and a couple old but very useful orphan apps. But back to the subject at hand…
I tried putting my data folders in SpecialFolder.ApplicationData, and it worked fine on my systems, but on some other Macs GetFolderItem didn’t see the folder. Does the user have to give permission? If so, how?
You can ask them to add some information. Some people will say that should be Apple information but seeing the problem it creates it makes sense to document that.
Maybe the way you are trying to do this, maybe another thing, I think there are some changes with Xojo 2019r2 what Xojo version are you using? maybe put the code you are using to create/copy the files to SpecialFolder.ApplicationData and the code you are using to read/write to it. Someone will be able to point at a solution.
Only on Catalina , to my knowledge.
User is asked if the app can access certain folders.
if they say no, problems…
Your app may also have trouble is it gets ‘translocated’ (search for that)
But show us the code you are using?
Here is my code to install the data folders and files:
’ Create the OpVPdata folder in SpecialFolder.ApplicationData,
’ and copy the three data folders and their contents into that folder
dim t as string
dim e as integer
dim x as boolean
dim f as FolderItem
dim Source as FolderItem
dim d as new MessageDialog
dim b as MessageDialogButton
’ Check for an OpVPdata folder, and create it if necessary
f = SpecialFolder.ApplicationData.child( “OpVPdata” )
if f.exists then ’ Does the OpVPdata folder already exist?
beep ’ yes, so ask whether to replace the data
d.icon = MessageDialog.GraphicCaution
d.message = “The OpVP data files already exist on this computer. Do you want to replace them?”
d.Explanation = “Replacing the data files will lose any changes you have made to games or players.”
d.ActionButton.caption = “Yes, replace with the new data”
d.AlternateActionButton.visible = true
d.AlternateActionButton.caption = “No, leave as is”
d.CancelButton.visible = true
d.CancelButton.caption = “Quit”
b = d.ShowModal
select case b ’ Branch on button pressed
case d.AlternateActionButton ’ User selected “No”
DoCopy = false ’ so leave the files as they are
case d.ActionButton ’ User selected “Yes”
e = DeleteEntireFolder( f, x ) ’ so delete the existing OpVPdata folder
if e <> 0 then
beep
MsgBox( “Error when deleting the existing OpVPdata folder.” )
quit
end if
DoCopy = true ’ Replace with new data folders
case d.CancelButton ’ User selected “Quit”
quit
end
end if
if DoCopy then ’ Copy the data folders and their contents into OpVPdata
t = "Copying the data files into the Application Support folder." +CR2
t = t + "This may take a few seconds."
TextArea1.text = t
app.VPdata = SpecialFolder.ApplicationData.child( "OpVPdata" )
if not app.VPdata.exists then app.VPdata.CreateAsFolder
if not app.VPdata.exists then
MsgBox( "Unable to create the OpVPdata folder." )
end if
Source = GetFolderItem( "Games" )
x = CopyFileOrFolder( Source, app.VPdata )
if x = false then return false
Source = GetFolderItem( "Players" )
x = CopyFileOrFolder( Source, app.VPdata )
if x = false then return false
Source = GetFolderItem( "RequiredFiles" )
x = CopyFileOrFolder( Source, app.VPdata )
if x = false then return false
end if
return true ’ Installation of the data files was successful
Then in the app’s Open event:
app.VPdata = SpecialFolder.ApplicationData.child( “OpVPdata” )
where app.VPdata is a public property FolderItem
And to access the data (example):
dim f as FolderItem
f = app.VPdata.child( “Player” ).child( “Speedy” )
I should have said
VPdata is a public property FolderItem in the app
Using Xojo 2016r4.1
This is a problem.
Games may not be where you think it is.
if you drag the Games folder so that it is in the resources, then you can find it and copy from it there.
Or you can ship a zip file and unpack that.
In Xojo 2016, there is no Specialfolder.resources
This is what I used: (for an app called MYApp)
[code]public function SpecialfolderResources() as folderitem
dim f as folderitem
#if targetMacOS
f =app.ExecutableFile.Parent.Parent.Child(“Resources”)
#else
#if debugBuild
f =app.executableFile.parent.child(“DebugMyApp Resources”)
#else
f =app.ExecutableFile.Parent.Child(“MyApp Resources”)
#endif
#endif
if f = nil or f.exists = false then
f = GetFolderItem(“”)
end if
return f
end function
[/code]