why can't I delete a folderitem and all subdirectories/files... wrote a method for it but it don't w

Here is some code that should work but doesn’t… And this is the 3rd iteration of the code (it is the cleanest that remains). The other versions I have beat on so much they don’t look like reasonable code anymore.

the goal of the method is to delete a folderitem. If the said folderitem is a directory, it will delete the contents prior to deleting itself. As folderitem.delete won’t delete itself and all subdirectories/files.

Sub deleteFolderitem(deleteItem as folderitem)
  
  if deleteItem = NIL then return // cant delete a NIL folderitem
  
  if not deleteItem.Exists then return // it doesnt exist so we cant delete it.
  
  if deleteitem.Directory then 
    // its a directory/folder
    
    if deleteItem.Count > 0 then 
      // we have subfolders and/or files in the directory that we need to delete first
      // going to use MBS plugins for getting the list of files(filesMBS) and directories(folderMBS)
      for each oFile as folderitem in deleteItem.FilesMBS
        
        oFile.delete
        
        if oFile.LastErrorCode > 0 then
          // we have an error on the file delete
          
          System.DebugLog "oFile.LastErrorCode = " + cstr( oFile.LastErrorCode ) + " for " + oFile.ShellPath
          
        end if
        
      next
      
      // no the directories
      for each oDir as folderitem in deleteItem.FoldersMBS
        // call myself(the method) recurisively to get the subdirectory clear.
        deleteFolderitem( oDir )
        
        // now that we are in theory empty we can delete the directory.
        oDir.delete
        
        if oDir.LastErrorCode > 0 then
          // we have an error on the file delete
          
          System.DebugLog "oDir.LastErrorCode = " + cstr( oDir.LastErrorCode ) + " for " + oDir.ShellPath
          
        end if
        
      next
      
    end if
    
    deleteItem.delete
    if deleteItem.LastErrorCode > 0 then 
      // we have an error on the directory delete
      
      System.DebugLog "deleteItem.LastErrorCode = " + cstr( deleteItem.LastErrorCode ) + " for " + deleteItem.ShellPath
      
    end if
    
    
  else  
    // its a file
    
    deleteItem.delete
    
    if deleteItem.LastErrorCode > 0 then 
      // we have an error on the file delete 
      
      System.DebugLog "deleteItem.LastErrorCode = " + cstr( deleteItem.LastErrorCode ) + " for " + deleteItem.ShellPath
      
    end if
    
  end if
End Sub

thanks… I know that I am doing something stupid.

I get either error code 101 (file not found) or 104 (file in use). the later is odd since the only thing that can be using these files are the app itself as it created them.

This is the code I wrote for this purpose. Perhaps this will help? Otherwise, at what point are you getting the errors?

Function Items_MTC(Extends f As FolderItem, includeInvisibles As Boolean = True) As FolderItem()
  dim r() as FolderItem
  if f <> nil and f.Exists and f.Directory then
    
    dim thisItem as FolderItem
    dim cnt as integer = f.Count
    
    // Do this as two separate loops to save some cycles
    if includeInvisibles then
      
      redim r( cnt - 1 )
      for i as integer = 1 to cnt
        thisItem = f.Item( i )
        r( i - 1 ) = thisItem
      next i
      
    else // Have to check for visibility
      
      for i as integer = 1 to cnt
        thisItem = f.Item( i )
        if thisItem.Visible then
          r.Append thisItem
        end if // isVisible
      next i
      
    end if // includeInvisibles
    
  end if // f <> nil and f.Exists and f.Directory
  
  return r
End Function

Function DeleteContentsOfFolder_MTC(Extends baseFolder As FolderItem) As Integer
  // Recursively deletes the contents of a folder, but keeps the folder in place.
  // If there is a problem anywhere along the way, returns an error code.
  
  dim errorCode as integer = 0
  
  if not baseFolder.Exists or not baseFolder.Directory then
    return errorCode
  end if
  
  dim queue() as FolderItem = baseFolder.Items_MTC
  while queue.Ubound <> -1
    
    dim thisItem as FolderItem = queue.Pop
    if thisItem.Directory then
      dim subItems() as FolderItem = thisItem.Items_MTC
      if subItems.Ubound <> -1 then
        queue.Append thisItem
        thisItem = nil
        for each f as FolderItem in subItems
          queue.Append f
        next
      end if
    end if
    
    if thisItem <> nil and thisItem.Exists then
      thisItem.Delete
      errorCode = thisItem.LastErrorCode
      if errorCode <> 0 then
        exit while
      end if
    end if
    
  wend
  
  return errorCode
End Function

Function DeleteRecursive_MTC(Extends f As FolderItem) As Integer
  // Deletes the contents of a folder, then the folder itself.
  // If there is an error along the way, returns the code
  
  dim errorCode as integer = 0
  if not f.Exists then return errorCode
  
  errorCode = f.DeleteContentsOfFolder_MTC()
  if errorCode = 0 then
    f.Delete
    errorCode = f.LastErrorCode
  end if
  
  return errorCode
  
End Function

I use this function without any problem in several project.

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
End Function

Ack! That’s a bug in my code. It should be TrueItem instead of Item. Thanks Pietro.

Pietro’s code is what I did put into the docs a while ago, I believe. It’s been tested and designed for optimal performance and handling all error cases.

It 's true. As I wrote, I use this function. I did not say that I wrote it. So thanks Thomas also from me. :wink:

@Scott boss:
You should use TrueFilesMBS and TrueFoldersMBS instead of the variants without true.

Everyone here is an update. For some unknown freaking reason neither my code nor any of yalls code works (I tried all the code in this thread). I am trying to delete a directory and a tar file that the app created itself. I get an errorcode 104 which means the file is in use.

Now here is the kick in the pants. In the same place I call the delete the folderitem method, I shell out and do a “/bin/sh -R /shell/path/to/folderitem” and it works 100% of the time. so the filesystem nor O/S has the handle on the foldereitem. It must be something within Xojo itself. It is a Xojo Console app.

Not sure if I need to open a bug report or not.

1 Like

Shouldn’t there be a shell command like rmdir in this line?

Scott, you say your app created the directory and tar file. Are you sure you have actually closed all connections to the file? If there is still one open the app can’t delete it. I’d check to make sure the file is actually closed.

Also, don’t forget to close and/or nil the FolderItem for the file AND the directory to ensure your app doesn’t have connection to them. Either will prevent deletion.

there isn’t a folderitem.close method. and if I NIL the folderitem, how do I do a folderitem.delete on it later? And if the (Xojo) app still had the file/directory open, then why does a /bin/rm -R /path/to/foldteritem work?

sorry if I am being dense here.

Use the copy constructor.

f2 = New FolderItem(f1)
f1 = nil
f2.Delete

Although, I wouldn’t expect a folderitem to be the culprit. Have you nil-ed out all streams?

[quote=194565:@scott boss]Everyone here is an update. For some unknown freaking reason neither my code nor any of yalls code works (I tried all the code in this thread). I am trying to delete a directory and a tar file that the app created itself. I get an errorcode 104 which means the file is in use.

Now here is the kick in the pants. In the same place I call the delete the folderitem method, I shell out and do a “/bin/sh -R /shell/path/to/folderitem” and it works 100% of the time. so the filesystem nor O/S has the handle on the foldereitem. It must be something within Xojo itself. It is a Xojo Console app.

Not sure if I need to open a bug report or not.[/quote]

Xojo calls OS API’s which use a different mechanism than what rm uses to remove the file
So they can vary in what they allow and do

Hmm. … was looking for a smart way to remove and entire tree. Wrote my own after checking this forum first.

[code]Private Sub EmptyThisFolder(f as FolderItem)
// empty entire folder (remove all files and subfolders)

Try
If f.Directory Then
If f.Count > 0 Then
Do
Dim g As FolderItem = f.Item(1)
If g <> Nil Then
If g.Directory Then
EmptyThisFolder(g) // recursive
g.Delete
Else
g.Delete
End If
Else
Exit
End If
Loop
End If
End If

Catch err As RuntimeException
RaiseEvent FileError(“Could not remove file or directory”)
End Try

End Sub[/code]

One should be careful about whether you are using .Item() or .TrueItem() depending on whether or not alias files should be followed.

Any reason why you did not simply use the example method at https://web.archive.org/web/20190324041130/http://documentation.xojo.com/api/files/folderitem.html.delete

or API 2 http://documentation.xojo.com/api/files/folderitem.html.Remove ?

I have been using it for years and it works flawlessly. Unless a file is locked, of course.

Was not aware of the official sample so just started writing my own. At least, as I see now, my code is much smaller and seems to work perfect also.

The docs say that .remove deletes a “file or folder”. Then there is an example to recursively delete a folder. With the old API.

The recursive way of deleting folders will fail if the structure is going deep (you’ll get a StackOverflow exception).
There are better methods which avoid recursion (basically just add each encountered folder to an array and empty every folder you find in this array).

Just in case someone stumbles on this thread…