How to delete files on Mac?

Im trying to figure out what the easiest way to delete files on a Mac is. Currently I am sending the file to specialFolder.Trash. However, if the folder has a file with the same name in it then it errors out, so I check the trash folder for the name and if it is there then I append a number to it and then send it to the trash. I can’t seem to get it to run reliably. I would like to be able to just remove the file out and not deal with the crazy way that Apple has the trash set up.

Anybody out there have a method for deleting files on a Mac that runs without problems? Just want to pass in the path and the file name and have it delete the file.
I am using it in an updater program. It downloads the new version of the program and then deletes the old program out. Thanks for any help you can offer.

From developer.xojo.com

Dim f As FolderItem f = GetFolderItem("Project Templates") f.Delete If f.LastErrorCode > 0 Then MsgBox(Str(f.LastErrorCode)) Else MsgBox("File deleted!") End If

Dim Today as new date and append to the file name to be deleted the time (after changing : to _) part of Today.

In short: look what the Finder do and mimick it (as you understand it).

And, I think this is the same under the two other Major OSes…

It would help if you post your code, otherwise it is pure guesswork where the problem might be.

My suspicion is that you don’t check in a loop and increment the number as required, but as I said, pure guesswork.

With MacFileOperation, you can move to trash:

Sub MoveFileToTrash(f as FolderItem) dim r as FolderItem call MacFileOperationMBS.MoveObjectToTrashSync(f, r, MacFileOperationMBS.kFSFileOperationDefaultOptions) End Sub

[quote=387021:@Markus Winter]It would help if you post your code, otherwise it is pure guesswork where the problem might be.

My suspicion is that you don’t check in a loop and increment the number as required, but as I said, pure guesswork.[/quote]

Sorry Markus, I don’t post on here too much. I didn’t think to post the code. Here it is. Thanks for taking a look.

[code]Public Function MoveFolderToTrash(fPathToFileToDelete as FolderItem, sFileToDelete as String) as String
Dim fPathForTheFileToDelete As FolderItem
Dim fPathForTheFileToTheTrash As FolderItem
Dim iModifier As Integer = 0
Dim sModifier As String = “”
Dim fTrashFolder As FolderItem = SpecialFolder.Trash
Dim sTrashFolder As String = fTrashFolder.AbsolutePath
Dim sError As String = “”

'--------------------------------------------------------------------------------
'Set fTheFolderOrFileToDelete to the passed in folder fPathToFoldeOrFileToDelete and the
'child sFolderOrFileToDelete file. Then check if it is nil or does not exist. If it is nil or does
'not exist then exit the method.
fPathForTheFileToDelete = GetFolderItem(fPathToFileToDelete.AbsolutePath).Child(sFileToDelete)
If fPathForTheFileToDelete = Nil Or Not fPathForTheFileToDelete.Exists Then Return “”

'----------------------------------------------------------------------------------
'For mac, because it will not send the file to the trash if it is a duplicate, it needs to
'have a modifier inserserted to the file name before it can be moved.
#If TargetMacOS Then
Do
'set the path for the file to the trash
fPathForTheFileToTheTrash = GetFolderItem(sTrashFolder).Child(sModifier+sFileToDelete)

  'check if it already exists in the trash. 
  If fPathForTheFileToTheTrash.Exists Then
    
    'if it does exist then increment the modifier as get its string value
    If iModifier < 100 Then
      iModifier = iModifier + 1
      sModifier = Str(iModifier)
      
      'rename the file to the name with the new modifier
      fPathForTheFileToDelete.Name = sModifier+sFileToDelete
    Else
      'msgbox fPathForTheFileToTheTrash.AbsolutePath
      sError = "Error = 100 limit"
      Exit Do
    End If
  Else ' the file does not exist in the trash.
    Exit Do
  End If
Loop

#EndIf

move the file To the trash
fPathForTheFileToDelete.MoveFileTo(fTrashFolder)

If fPathForTheFileToDelete.LastErrorCode <> 0 Then ’ error 5000
sError = GetFolderItemErrorCode(fPathForTheFileToDelete.LastErrorCode)
MsgBox sError
End If

return sError

End Function
[/code]

[quote=387041:@Christian Schmitz]With MacFileOperation, you can move to trash:

Sub MoveFileToTrash(f as FolderItem) dim r as FolderItem call MacFileOperationMBS.MoveObjectToTrashSync(f, r, MacFileOperationMBS.kFSFileOperationDefaultOptions) End Sub[/quote]
Thanks Christian for the suggestion. I’m trying to keep my software limited to what I have without using the plugins. If I absolutely need to, I will use MBS. Currently have a license because I use their curl plugin. I wasn’t aware of this method from mbs so If I can’t figure it out, Ill have some good code to fall back on.

As far as I can see you check if the filename exists in the trash, but what if

File in the trash:

MyFile.txt

File in the folder:

MyFile.txt
MyFile1.txt

Now you‘ll get an error on trying to rename MyFile.txt to MyFile1.txt because that already exists in the folder!

So you would get an error here:

'rename the file to the name with the new modifier fPathForTheFileToDelete.Name = sModifier+sFileToDelete

How about letting Finder move it to the Trash (the way it always does, along with all the renaming-if-neccessary)?

Dim sh As New Shell sh.execute "osascript -e 'tell application ""Finder"" to delete (POSIX file """ + TheFolderItemToBeMovedToTrash.NativePath + """ as alias)'"

Just be aware that doing it like this may cause the TheFolderItemToBeMovedToTrash instance to pick up the new location (in the Trash). It would then report “TheFolderItemToBeMovedToTrash.Exists = true” (in the new Trash location).
And AppleScript is a no-go if you think about bringing your app to the Mac App Store.

http://documentation.xojo.com/index.php/FolderItem.Delete

Already suggested is meant to do the job. Is there something we do not know about it (for searching alternate ways) ?

[quote=387123:@Emile Schwarz]http://documentation.xojo.com/index.php/FolderItem.Delete

Already suggested is meant to do the job. Is there something we do not know about it (for searching alternate ways) ?[/quote]

Jeffery wants the file to be moved to the trash the same way as deleting something in the Finder.

FolderItem.Delete deletes the file immediately without moving it to the trash.

I may just revisit the folderItem.delete. The only reason for sending to the recycle bin is so there is a level of redundancy in the update process. If the update process fails on any one of the files its replacing, the user will be able to manually recover the only file. It’s just a safeguard that I can probably bypass. One problem that I had with FolderItem.delete was that I was getting random errors back saying something to the effect that I didn’t have permissions to delete a folder.

Here is my function to delete a folder (swiped from the Forum I think):

[code]Private Function DeleteEntireFolder(theFolder as FolderItem, continueIfErrors as Boolean = false) as Integer

// Returns an error code if it fails, or zero if the folder was deleted successfully

dim returnCode, lastErr, itemCount as integer
dim files(), dirs() as FolderItem

if theFolder = nil or not theFolder.Exists() then
return 0
end if

// Collect the folder‘s contents first.
// This is faster than collecting them in reverse order and deleting them right away!
itemCount = theFolder.Count
for i as integer = 1 to itemCount
dim f as FolderItem
f = theFolder.TrueItem( i )
if f <> nil then
if f.Directory then
dirs.Append f
else
files.Append f
end if
end if
next

// Now delete the files
for each f as FolderItem in files
f.Delete
lastErr = f.LastErrorCode // Check if an error occurred
if lastErr <> 0 then
if continueIfErrors then
if returnCode = 0 then returnCode = lastErr
else
// Return the error code if any. This will cancel the deletion.
return lastErr
end if
end if
next

redim files(-1) // free the memory used by the files array before we enter recursion

// Now delete the directories
for each f as FolderItem in dirs
lastErr = DeleteEntireFolder( f, continueIfErrors )
if lastErr <> 0 then
if continueIfErrors then
if returnCode = 0 then returnCode = lastErr
else
// Return the error code if any. This will cancel the deletion.
return lastErr
end if
end if
next

if returnCode = 0 then
// We‘re done without error, so the folder should be empty and we can delete it.
theFolder.Delete
returnCode = theFolder.LastErrorCode
end if

return returnCode

exception exc
theException = new ErrorException(exc, currentMethodName)
End Function
[/code]

That method is one of the examples on the http://documentation.xojo.com/index.php/FolderItem.Delete page.

It works well, but it doesn’t move files to the trash. It is convenient if you need to recursively delete a populated directory and aren’t worried about it being irreversible.

[quote=387118:@Jürg Otter]How about letting Finder move it to the Trash (the way it always does, along with all the renaming-if-neccessary)?

Dim sh As New Shell sh.execute "osascript -e 'tell application ""Finder"" to delete (POSIX file """ + TheFolderItemToBeMovedToTrash.NativePath + """ as alias)'"

Just be aware that doing it like this may cause the TheFolderItemToBeMovedToTrash instance to pick up the new location (in the Trash). It would then report “TheFolderItemToBeMovedToTrash.Exists = true” (in the new Trash location).
And AppleScript is a no-go if you think about bringing your app to the Mac App Store.[/quote]
The user may not have the Finder running at the time you invoke this script (like if (s)he has installed Path Finder or has quit the Finder to, say, free some RAM or any other reason). In such a case, the script will launch the Finder to do the task. The user will see the Finder launching (which (s)he probably doesn’t want to), wait for it to restore windows and then do the move to the trash; the user will then have to quit the Finder again.
Not a good practice in my opinion (and I recall seeing Apple saying the same thing for these reasons in a web page (perhaps in the interface guidelines?)).

I wasn’t aware that the system could operate without Finder running

Even on Classic Mac OS you could use e.g. an AppleScript

tell application "Finder" to quit

and this works still on macOS 10.14 :wink:

That will not work anymore with macOS10.15 - it is not possible to use AppleScript to let Finder delete/move files.

That AppleScript way worked just fine at it’s time.

It still works. But requires quite some overhead (AppleEvents usage description, codesign entitlements), and is no longer a good user experience (“the .app wants to automate your system. allow? yes/no”).
Up until macOS 10.13 (or even 10.14.4/5) that’s been fine - for our needs.

Right - an edge case. As a user I might even be happy if Finder gets re-started :wink:

Anyway… This is how I move files/directories/an-old.app to Trash on macOS nowadays:
NSFileManager trashItemAtURL:resultingItemURL:error:

[code]//These Declares require macOS 10.8+ (Xojo 2017.03 builds for OS X 10.9+)
Declare Function trashItemAtURL Lib “Cocoa” selector “trashItemAtURL:resultingItemURL:error:” ( NSFileManagerInstance As Integer, inUrl As Integer, outUrl As Integer, outError As Integer ) As Boolean
Declare Function defaultManager Lib “Cocoa” selector “defaultManager” ( NSFileManagerClass As Integer ) As Integer
Declare Function NSClassFromString Lib “Cocoa” (className As CFStringRef) As Integer
Declare Function NSerrorlocalizedDescription Lib “Cocoa” selector “localizedDescription” (NSErrorInstance As Integer) As CFStringRef
Declare Function NSURLfileURLWithPathIsDirectory Lib “Cocoa” selector “fileURLWithPath:isDirectory:” (NSURLClass As Integer, path As CFStringRef, directory As Boolean) As Integer

Dim newLocation, NSError As Integer
Dim bSuccess As Boolean = trashItemAtURL( defaultManager( NSClassFromString( “NSFileManager” ) ), NSURLFileURLWithPathIsDirectory( NSClassFromString( “NSURL” ), poFolderitem.NativePath, poFolderitem.Directory ), newLocation, NSError )

If (bSuccess = False) Then
Dim sErrorMessage As String = NSErrorlocalizedDescription( NSError )
//cope with it
end if[/code]