Deleting a file or directory may seem a trivial task and it often is, but it has some hidden quirks that Groovy may help you with. This recipe will enlist and give details about several methods to delete a file or a directory.
Let's assume that we have two java.io.File
variables: one pointing to a normal file and another to a nonempty directory with several subdirectories in it. For example:
def dir = new File('./tmp1') def file = new File('./tmp2/test.txt')
As you know from Java, the java.io.File
class has a delete
method and it works perfectly in many situations. But it will only delete a normal file or an empty directory. So, to delete a nonempty directory you need to write a recursive function in Java. Also, in most of the situations, the delete
method will not throw any exceptions; it will just return false if it fails to delete a file or directory.
Let's explore several ways to delete things on the file system.
deleteDir
in the java.io.File
class. Let's try to delete our file
and directory
with both the delete
and deleteDir
methods and print the result:println file.deleteDir() println file.delete() println dir.delete() println dir.deleteDir()
false true false true
The first method call returns false
, because the given file
is not a directory. The second one successfully deletes the file
and returns true
. The third one returns false
because we try to delete a nonempty directory. The last one returns true
, because we recursively delete the root folder and its subfolders with the Groovy's deleteDir
method.
In order to ensure that a file or a directory is deleted, you always need to check the result of the delete
or deleteDir
method. In a scenario where several files or folders have to be deleted, you may end up with a lot of noisy conditional statements. Not pretty. An elegant solution to the issue posed above is possible by resorting to Groovy's metaprogramming features. The java.io.File
class can be enhanced with a new method, safeDelete
:
File.metaClass.safeDelete = { if (exists()) { if (isDirectory()) { if (!deleteDir()) { def msg = "Unable to delete a directory: ${name}" throw new IOException(msg) } } else { if (!delete()) { def msg = "Unable to delete a file: ${name}" throw new IOException(msg) } } } }
Groovy metaprogramming and the metaClass
object are discussed in more detail in Chapter 9, Metaprogramming and DSLs in Groovy. In short, the previous code adds a new method to the java.io.File
class called safeDelete
. The new method ensures that the file exists; then it checks if the File
is a directory, and calls a recursive delete on it. If the File
object points to a file, it calls a normal delete
. If either the delete
or deleteDir
operations return false
, the method throws an IOException
.
After you have extended the java.io.File
class, then you can simply call the method on any File
instance:
file.safeDelete() dir.safeDelete()
By using this method, you can avoid many conditional statements and implement simpler exception handling.
One more way to manipulate files is by using Groovy's built-in Apache Ant support. Through the groovy.util.AntBuilder
class, you can get access to all the common Ant tasks including the delete
task.
def ant = new AntBuilder() ant.delete(dir: file.absolutePath, failonerror:false)
Ant's file-handling capabilities are quite extended, especially when it comes to copying files around.