Sidebar

How can I get more information about why calls to file.delete() is randomly fail?

0 votes
1.4K views
asked Aug 16, 2018 by david-f-5427 (1,600 points)

I have a mapping node with the following code:

function deleteFiles(directoryToEmptyOut) {
   var directory = new java.io.File(directoryToEmptyOut);
   var files = directory.listFiles();  

   for (var currentFile = 0; currentFile < files.length; currentFile++) {
      qie.debug('Deleting ' + files[currentFile]);


      try {
         files[currentFile].delete();
      } catch (err) {
         qie.debug('Unable to delete ' + files[currentFile] + ' - ' + err);
      }
   }
}

This code sometimes successfully removes all files and sometimes appears to have randomly failed and, as a result, some files are left in the directory. I've tried to log out any error but I don't see any log statements. How can I find out more about why these files are not being deleted? 

1 Answer

0 votes

Unfortunately, the java.io.File delete() method does not throw any exceptions if it fails. It simply returns the true/false -> success/fail flag. You can attempt to glean a little more info about the file at the attempted time of deletion by adding the following if-test:

if (!files[currentFile].canWrite()) {
  qie.debug("No write permission");
} else if (files[currentFile].delete()) {
  qie.debug("delete successful");
} else {
  qie.debug("delete failed - unknown reason");
}

 

In this particular case, most debug statements would report the "unknown reason".

QIE's code wizard has a file delete method - qie.deleteFile(...). However, it simply calls file.delete() and if we get a false (meaning the file deletion failed), we throw an IOException but it only contains a static message stating "Unable to delete file 'file_name'." (because the file.delete() call only provided us with a false return value).  This, of course, is not any more helpful than directly calling java.io.File.delete()... So, our code wizard approach wouldn't be much more helpful in trying to figure out why files are sometimes not deleted.

try {
  qie.deleteFile("fileName");
} catch (err) {
  qie.debug(err);
}

The above code would, upon failure to delete, only log "Unable to delete fileName".

As of Java 1.7, you have Java's NIO package: https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#delete(java.nio.file.Path) 

This package's Files.delete() method does throw an IOException that can be caught in script to provide an exact reason for the delete call's failure.

Here's a snippet of Java 1.7's NIO Files deletion:

var file = files[currentFile]; //NOTE: this is a java.io.File object
var nioFilePath = file.toPath(); //NOTE this is a java.nio.file.Path
try {
    qie.debug("Deleting file: " + nioFilePath.toString());
    java.nio.file.Files.delete(nioFilePath);
} catch (err) {
  qie.debug("Deleting file " + nioFilePath.toString() + " failed. " + err);
}

 

As far as thoughts about why the file.delete() sometimes fails here and there, consider if any other code is re-accessing and locking up those file.

Also of note, we have experienced delete fails when attempting to delete large numbers of files in directories on Windows systems. This means even using NIO's Files.delete() method would still not result in all files being deleted. The cause seems to be that directory table seems to occasionally lag behind while updating itself as files are deleted, causing almost a sort of race condition which leaves random files undeleted. One workaround to this is to wrap the call to file.delete() or qie.deleteFile() in a loop that attemps to delete the file for a specified number of retries with a small delay in between retries, to allow the OS's file table to be updated. If the delete calls still fail after the specified number of retries, the file(s) in question would be left behind in the directory. If this is the case, you could adjust the pause time and/or the number of retries to satisfy your requirements. Here's an example of the retry/pause implementation:

var maxRetries = 3;
for (var i = 0; i < maxRetries; i++) {
  if (file.delete()) {
    break;
  } else {
    qie.pause(20); //millis
  }  
}
answered Aug 16, 2018 by david-f-5427 (1,600 points)
edited Aug 17, 2018 by david-f-5427
...