Java : Delete a directory with contents

The Files.delete method can delete an empty directory, but cannot delete a directory with contents. In this article, I will show you how to delete an entire directory with contents.

Note:


Code example

Let's take a look at a code example.

public void deleteAll(Path dir) throws IOException {

    Files.walkFileTree(dir, new SimpleFileVisitor<>() {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            if (exc != null) {
                throw exc;
            }

            Files.delete(dir);
            return FileVisitResult.CONTINUE;
        }
    });
}

The deleteAll method deletes an entire directory with contents.

This code example is based on the FileVisitor usage examples in the official API specification.

Warning

  • Be careful not to delete important files and check the operation.

Description

public static void delete(Path path) throws IOException
Deletes a file.

The Files.delete method can delete a file or an empty directory. But cannot delete a directory with contents.

For example, you will prepare the following files and directories. (Commands are executed in PowerShell on Windows)

PS D:\java-work> tree /F
...
D:.
│  aaa.txt
│
├─dir1
└─dir2
        bbb.txt
  • aaa.txt : file
  • dir1 : empty directory
  • dir2 : directory with contents (bbb.txt).

You try to delete the files and directories with Files.delete.

final var aaa = Path.of("D:", "java-work", "aaa.txt");
System.out.println(aaa); // D:\java-work\aaa.txt
System.out.println(Files.isRegularFile(aaa)); // true

// Delete OK
Files.delete(aaa);
System.out.println(Files.notExists(aaa)); // true

final var dir1 = Path.of("D:", "java-work", "dir1");
System.out.println(dir1); // D:\java-work\dir1
System.out.println(Files.isDirectory(dir1)); // true

// Delete OK
Files.delete(dir1);
System.out.println(Files.notExists(dir1)); // true

final var dir2 = Path.of("D:", "java-work", "dir2");
System.out.println(dir2); // D:\java-work\dir2
System.out.println(Files.isDirectory(dir2)); // true

try {
    // Delete NG
    Files.delete(dir2);
} catch (IOException e) {
    System.out.println(e);
}

// Result
// ↓
//java.nio.file.DirectoryNotEmptyException: D:\java-work\dir2
PS D:\java-work> tree /F
...
D:.
└─dir2
        bbb.txt

The Files.delete method can delete the aaa.txt and the dir1. But cannot delete the dir2, because it is not empty.

To delete the dir2, you must first delete all contents in the dir2.


public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor) throws IOException
Walks a file tree.

The Files.walkFileTree method walks through the list of files and directories.

For example, you will prepare the following files and directories.

PS D:\java-work> tree /F
...
D:.
└─target-dir
    │  aaa.txt
    │  bbb.txt
    │
    ├─dir1
    │  │  ccc.txt
    │  │  ddd.txt
    │  │
    │  └─dir1-2
    │          eee.txt
    │          fff.txt
    │
    └─dir2
            ggg.txt
            hhh.txt

You can access all the files and directories in the target-dir with Files.walkFileTree. To access them, use a FileVisitor and receive a callback. This time, we will use a SimpleFileVisitor which is the subclass of the FileVisitor.

final var target = Path.of("D:", "java-work", "target-dir");
System.out.println(target); // D:\java-work\target-dir
System.out.println(Files.isDirectory(target)); // true

Files.walkFileTree(target, new SimpleFileVisitor<>() {
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        System.out.println("visitFile          : " + file);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
        System.out.println("postVisitDirectory : " + dir);
        return FileVisitResult.CONTINUE;
    }
});

// Result
// ↓
//visitFile          : D:\java-work\target-dir\aaa.txt
//visitFile          : D:\java-work\target-dir\bbb.txt
//visitFile          : D:\java-work\target-dir\dir1\ccc.txt
//visitFile          : D:\java-work\target-dir\dir1\ddd.txt
//visitFile          : D:\java-work\target-dir\dir1\dir1-2\eee.txt
//visitFile          : D:\java-work\target-dir\dir1\dir1-2\fff.txt
//postVisitDirectory : D:\java-work\target-dir\dir1\dir1-2
//postVisitDirectory : D:\java-work\target-dir\dir1
//visitFile          : D:\java-work\target-dir\dir2\ggg.txt
//visitFile          : D:\java-work\target-dir\dir2\hhh.txt
//postVisitDirectory : D:\java-work\target-dir\dir2
//postVisitDirectory : D:\java-work\target-dir

FileVisitor methods are called back at the following times.

  • The visitFile method is called when a file is found.
  • The postVisitDirectory method is called after all files in a directory are called on the visitFile method.

In other words, if you delete the file with visitFile, the directory will be empty when postVisitDirectory is called.

Note

  • The Files.walkFileTree does not walk symbolic links by default. You use FileVisitOption.FOLLOW_LINKS if you want to access even the destination of symbolic links.

Conclusion

Finally, I wrapped it up as a little utility class.

public class FileUtils {
    private FileUtils() {
    }

    public static void deleteAll(Path dir) throws IOException {
        Objects.requireNonNull(dir);

        Files.walkFileTree(dir, new SimpleFileVisitor<>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Files.delete(file);
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                if (exc != null) {
                    throw exc;
                }

                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }
}

You will delete the following target-dir directory with contents.

// --- PowerShell ---
//PS D:\java-work> tree /F
//...
//D:.
//└─target-dir
//    │  aaa.txt
//    │  bbb.txt
//    │
//    ├─dir1
//    │  │  ccc.txt
//    │  │  ddd.txt
//    │  │
//    │  └─dir1-2
//    │          eee.txt
//    │          fff.txt
//    │
//    └─dir2
//            ggg.txt
//            hhh.txt

final var dir = Path.of("D:", "java-work", "target-dir");
System.out.println(dir); // D:\java-work\target-dir
System.out.println(Files.isDirectory(dir)); // true

FileUtils.deleteAll(dir);

System.out.println(Files.notExists(dir)); // true

The FileUtils.deleteAll method was able to delete the target-dir directory with contents.


Related posts

To top of page