Needs an update, but how?

OK, I have realized that this piece of code is in desperate need of an update as it’s been around for 20 + years now. It runs fine on four or five of my computers (Macs of various age and a Windows 11 laptop), but not on a customer computer (2013 iMac) for some to me unknown reason. It refuses to extract the “file” as a Folderitem, sometimes !???, and therefore crashes in the code that follows this code. The file is a plain text file and is supposed to end up in the folder where the app is. What would be the updated equivalent? Any suggestions ?

Var file As FolderItem
file = GetFolderItem(“SomeFileName”)
If file <> Nil Then
Var output As TextOutputStream
output = TextOutputStream.Create(file)
output.WriteLine(“Hello world”)
output.Close
End If

When posting code highlight it and press the </> button. It will format it and prevent " from being turned into 66 and 99s. The new version of GetFolderItem is as follows:

Var file As New FolderItem(“SomeFileName”)

https://documentation.xojo.com/api/files/folderitem.html#folderitem-constructor1

Where are you expecting the file to be? If it is a fixed path then that could be the cause of your problem. There are SpecialFolders available to help you correctly locate files, for example:

Var DocumentsFolder as FolderItem = SpecialFolder.Documents

https://documentation.xojo.com/api/files/specialfolder.html

You can then refer to files within that folder using child method.

Var DocumentsFolder as FolderItem = SpecialFolder.Documents
file = DocumentsFolder.Child( "SomeFileName.txt" )

It would also be best to check isWritable before attempting to create the file.

if file is nil then
   // Folderitem cannot be creaated
else
   if file.IsWriteable then
      // Create file
   else
      // The file cannot be written to.
   end if
end if
1 Like

You also need to wrap that code in a try-catch. TextInputStream now throws exceptions.

Where are you expecting this file to be?
If you are hoping it is ‘next to the app’, you probably have it in Applications
You probably have permission to read and write there… but your customers/clients won’t.

if you Mac app is installed on a usb disc, or desktop, it is probably running ‘sandboxed’ , using translocation. The file is not local to your app any more, because your app is ‘running from’ a different location.
And it certainly would not have permission to create files in Applications or similar system locations.

You need to have the file in some sub folder of Specialfolder.ApplicationData

file = specialfolder.applicationdata.child(“SomeFileName”)

To avoid translocation, ensure your app is signed and notarised, and located in Applications, nowhere else.

After all that, you can update the code to use newer methods of folderitem if you like. (the API1 methods still work)

You could add it as a resource for your app, and then use:

file = SpecialFolder.Resource (name)

to get a folderitem for it.

name would be whatever the IDE calls the file when you drag/drop it into the navigation pane of the IDE.

Thanks guys for all your suggestions. My primary goal with my question is to get it to behave in a consistent way, and not so much what the file does and where it goes. I have updated the code according to your suggestions and sent it to the user having the problem for review. As before, it does work here.

As you appear to be trying to write to the file, if it is in applications then it will never work. Writing there is not allowed. Where is it?

1 Like

Exactly. Maybe this is one of the changes made as per suggestions.
It should be said that the same issue will arise with this:

file = SpecialFolder.Resource (name)

Any file opened in this way would need to be written somewhere else

Yes indeed. I had not, perhaps, grasped what all OP’s needs are WRT the file.

@Claes_Lundstrom : what OS and version are you running and what OS and version is the customer running?

All Mac OS. I have tested it on a range of five Macs from modern to ancient, and it works perfectly The one with a problem is an iMac 2013 I think

Please confirm the location of the file. We cannot provide better help without understanding what you are trying to do.

You may perhaps get away with it in very limited circumstances on an Intel Mac, but likely never on a production application and especially on an Apple Silicon Mac. It would break signatures for a start. If the file is “internal” to the application then you can use a subfolder in “Application Support” (SpecialFolder.ApplicationData) or perhaps a “Preferences” subfolder (SpecialFolder.Preferences).

User saved files should be stored within the SpecialFolder.Documents folders.

These rules are from Apple (and Microsoft) and are not just advisory, they are mandatory. The operating system will prevent you from breaking them, without elevated privileges.

It is located next to the app, for now and during testing. I am aware of the “forbidden zone” in the apps folder and therefore run it outside that for now. I just want to understand the inconsistency of it working sometimes and sometimes not. I will for sure place the file properly what I have sorted the problem. I’m currently waiting for feedback from the user.

Even with elevated privileges, writing to the app’s bundle will break its signature and the app won’t launch further (as you mentioned). Also, there are other mechanisms that may prevent one to write in the app’s own bundle (permissions, extended attributes, system integrity protection, …).

Yes yes yes but which versions?

But if the app runs translocated, the file is not ‘next to the app’, no matter what your eyes tell you.

(You think your app is in a USB drive, or the desktop, or similar
You put the file next to it.
*Mac OS runs your app, but makes it be ‘inside’ a completely different location, and your file is not there.) When this happens, your app to all intents and purposes is actually in some randomly named location such as

/private/var/folders/4d/x76c3kn158q0mvbcjh8dy12h0000gn/T/AppTranslocation/FD855598-DFCA-4A82-9A0D-229C0C99035B/d/My.app
)

Nonetheless, if you put the file in specialfolder.applicationdata , it will work on all machines, sandboxed or not.

If you don’t want to do that, then one possible way to avoid this issue is…

  • on the user’s machine, use Finder to move the app from wherever it is, into Applications. (That move will stop the quarantine flag)
  • Then move it and the file to somewhere else , where the file can be written

(A slightly less common reason, but one that catches me out now and then, is where the user has their documents folder fully synched by iCloud.
A file that appears to be present, fails to open when requested, because it is actually only in the cloud and not downloaded/delivered to the app in a timely manner.
Or perhaps is being synched to the cloud at the time it is being accessed - who knows)

In my programs, when the user is offered an opportunity to download some information as a file, I have always just had it downloaded to the Desktop folder or some subfolder of that folder. My idea was that that was easy to find.

Are you implying that this is not kosher? I am not aware that the Documents folder is “mandatory”. It is possible that users of my programs would run into problems when running my app because of this?

I only produce Mac programs.

On the Mac, downloads should go in the Downloads folder.

Or whatever location the user has chosen to set to receive downloads. Which is the Desktop, in my case.

Is this a decision that you have made personally in System settings or whatever?

I have noticed recently when using software that a pop-up might appear asking permission for a program to download things to the Documents folder. It this all a System thing that happens automatically if my program or any program initiates such a download (writing a file)? I have not seen this for the Desktop folder, perhaps just because I have not used a program that tried to do this. I would assume, if the behavior is deep in the macOS itself, that the Desktop folder would be treated the same way.

I am curious if the Downloads folder is somehow different. That the recent macOS versions would still silently accept having stuff download by a program into the Downloads folder.

I personally have used a folder which is a subfolder of the SpecialFolder.ApplicationData folder. For the name of that subfolder folder, I use the Bundle Identifier which should be unique and distinguishable from the other folders created by other apps that also live in the SpecialFolder.ApplicationData. This is where I place files that, for example, preserve state between different invocations of the program.

The user is not expected to have any knowledge of this location. (unless they are calling me about some bug that I have managed to introduce and I am trying to guide them into recovering from it :thinking:).

Apple encourages this by making it slightly difficult to navigate to this location in the Finder.

At least to the best of my knowledge, Mac OS does not throw up “alarming” pop-ups when your app saves some data here.