During testing a new app, I was using a database program (Tadpole) to examine the files that the new app was creating…
and kept running into what I thought were strange errors… It turned out that Tadpole had a lock on the database the that other app was trying to manipulate.
So I came up with a simple method that checks for “who has my file” [this is for macOS only]
a bit brute-force, but it seems to do the job
Public Function file_is_busy(f as FolderItem) as boolean
Dim sh As New shell
Dim s As String
Dim v() As String
Dim x As Integer
sh.Execute("lsof "+f.ShellPath)
s=Trim(ReplaceLineEndings(sh.result,EndOfLine.UNIX))
If s="" Then Return False // file is not being held
//
//
v=Split(s,EndOfLine.UNIX)
s=v(1)
x=InStr(s," ")
s=Trim(Left(s,x))
MsgBox("File is Busy"+endofline+"The '"+s.Uppercase+"' application currently has the '"+f.DisplayName+"' file open.")
Return True
End Function
the “whatsopen” utility allows you to see what app is holding a file by having it opened .
for me it’s almost the same
your’s has the advantage of being xojo-made, so you can code something based on the result.
I wouldn’t recommend using this function to detect if the file is not writeable, the reason being is that if the user has selected the file in the Finder, you can have not only the Finder ‘using it’ but also ‘Quicklook’.
Check the meta data on the file, instead. I’m pretty confident that you’ll find folderitem.isWriteable will be false. You can also check folderitem.isReadable to make sure that various permissions system in the macOS are allowing your file to be opened, i.e. Actual user permissions, App Sandbox security and probably others I haven’t yet come across.
Well I wrote this function to determine if my new apps database was open by another app … which during testing it is as I check the database being created…
However now I find that in one of the new apps processes , I can’t make it LET GO of the file
function ONE(f as folderitem)
... check if file (f) exists, if so bail out
... create an SQLite datatabase for (f)
... create a bunch of tables
... CLOSE THE database
... call TWO(f)
END FUNCTION
function TWO(f as folderitem)
.... is the folderItem in use? ..... YES IT SEEMS TO BE
.... do other stuff
END FUNCTION
ONE(f) is used to create a new Database
TWO(f) is used to open/use an Existing one
so depending… the sequence is
ONE(f) -> TWO(f)
TWO(f) // this seems to be fine
its when ONE(f) is called first, it doesn’t “let go”
I have call DB.CLOSE
set DB=NIL
even stored the NativePath from F, set it to NIL and created it again
How does one release the hold on a file so it can be recreated elsewhere without issue?
Tracking these kind of issues down can be a pain, you need to look at everything and I mean everything that comes from the database object. I’d start by creating a simple application, that connects to a database and reads a bit from it. Make sure at the end (using LSOF) that everything has been closed correctly.
Once you can confirm that you have some code working that is correctly releasing the lock on the file, then you add in more complex tasks to the sample application until you figure out where you’re retaining the lock.
I had to do this recently (not with a database app) where there were several elements created way down stream that were causing the lock on the file to be retained, even when I’d thought I’d gotten everything. It took me two days to track it down to one line of code.