Java Check If Directory Is Empty: Files.list() and More

Java check if directory is empty with Files.list() or newDirectoryStream(), closing the stream, files and missing paths, hidden files and subfolders.

Diagram comparing a lazy DirectoryStream that reads one entry with File.list that loads every name in the folder into an array

To check if a directory is empty in Java, we open it with Files.list() or Files.newDirectoryStream() and ask for the first entry, and when there is none, the directory is empty. Both methods read the folder lazily and stop after the first entry, so the check never loads every name, even in a folder with a million files.

We check for empty folders before an import job starts processing an inbox, and when cleaning up folders that were left empty after a job moved their files away.

The following example checks a freshly created inbox folder.

Path inbox = Files.createTempDirectory("inbox");          // new, empty folder
Optional<Path> first;
try (Stream<Path> entries = Files.list(inbox)) {
    first = entries.findFirst();
}
boolean empty = first.isEmpty();                           // true

Notice the try-with-resources block, because the stream holds an open directory handle until we close it. We write a reusable check, handle paths that are files or missing, decide what to do with hidden files, compare the older File.list() and find empty subfolders in a tree.

1. Checking With Files.newDirectoryStream()

A DirectoryStream iterates over the entries of one folder, reading them from the operating system as we go. Calling iterator().hasNext() reads at most one entry, which answers our question without touching the rest of the folder.

Diagram comparing a lazy DirectoryStream that reads one entry with File.list that loads every name in the folder into an array
A lazy check stops after the first entry, while File.list() builds an array of every name before we can test its length

The isEmpty() method closes the stream in every case and returns the answer as a boolean.

static boolean isEmpty(Path dir) throws IOException {
    try (DirectoryStream<Path> entries = Files.newDirectoryStream(dir)) {
        return !entries.iterator().hasNext();
    }
}
Path uploads = Files.createTempDirectory("uploads");
boolean before = isEmpty(uploads);                         // true
Path photo = Files.writeString(uploads.resolve("cat.jpg"), "x");
boolean after = isEmpty(uploads);                          // false
Path sub = Files.createDirectory(Files.createTempDirectory("music").resolve("rock"));
boolean parentEmpty = isEmpty(sub.getParent());            // false, a subfolder counts too

Any entry makes the folder non-empty, whether it is a file, a subfolder or a symbolic link. The check looks at one level only, so a folder that contains an empty subfolder is not empty.

2. Check If a Directory Is Empty With Files.list()

The method Files.list() wraps the same lazy listing in a Stream<Path>. The short-circuiting findAny() stops at the first element, so the stream version is as fast as the iterator version and reads well in code that already uses streams.

static boolean isEmptyDir(Path dir) throws IOException {
    try (Stream<Path> entries = Files.list(dir)) {
        return entries.findAny().isEmpty();
    }
}
Path reports = Files.createTempDirectory("reports");
boolean noReports = isEmptyDir(reports);                   // true
Path q3 = Files.writeString(reports.resolve("q3.pdf"), "x");
boolean hasReports = !isEmptyDir(reports);                 // true

A one-line version such as Files.list(dir).findAny().isPresent() appears in many tutorials. It has two bugs, because isPresent() is true for a folder that is not empty, and the stream is never closed. In a service that runs the check every few seconds, the leaked handles add up until the process fails with Too many open files.

3. Paths That Are Files or Do Not Exist

Both methods throw when the path is not a folder, and that is often what we want, because a wrong path in a configuration should fail loudly. The exact exceptions depend on the case.

PathFiles.list() / newDirectoryStream()File.list()
Empty folderEmpty stream, no entriesEmpty array
Folder with entriesStream with entriesArray of names
Regular fileNotDirectoryExceptionnull
Missing pathNoSuchFileExceptionnull
No read permissionAccessDeniedExceptionnull
Path dir = Files.createTempDirectory("data");
Path file = Files.writeString(dir.resolve("orders.csv"), "x");
boolean fileCheck = isEmpty(file);                         // NotDirectoryException
boolean missingCheck = isEmpty(dir.resolve("archive"));    // NoSuchFileException

When a missing folder counts as nothing to process, we check the type first and treat everything that is not a folder as empty. The method name says that, so nobody mistakes it for a strict check.

static boolean hasNoEntries(Path dir) throws IOException {
    if (!Files.isDirectory(dir)) {
        return true;                          // missing or not a folder
    }
    try (Stream<Path> entries = Files.list(dir)) {
        return entries.findAny().isEmpty();
    }
}
Path base = Files.createTempDirectory("base");
boolean nothingToDo = hasNoEntries(base.resolve("not-mounted"));   // true

4. Hidden Files and Junk Entries

Hidden files count as entries. Dot files such as .env are hidden on Linux and macOS only in file managers and plain ls output, and Java lists them like any other file. macOS Finder also drops a .DS_Store file into folders it opens, and Windows Explorer may create Thumbs.db.

Say an import job polls a shared inbox folder and starts a batch when the folder is not empty. After someone opens the folder in Finder, the job finds .DS_Store, starts a batch and fails with no CSV files to read. We avoid that by asking for the entries the job cares about, using a glob pattern with newDirectoryStream().

static boolean hasCsvFiles(Path dir) throws IOException {
    try (DirectoryStream<Path> csvFiles = Files.newDirectoryStream(dir, "*.csv")) {
        return csvFiles.iterator().hasNext();
    }
}
Path shared = Files.createTempDirectory("shared");
Path junk = Files.writeString(shared.resolve(".DS_Store"), "x");
boolean strictlyEmpty = isEmpty(shared);                   // false, .DS_Store counts
boolean work = hasCsvFiles(shared);                        // false, no CSV files
Path orders = Files.writeString(shared.resolve("orders.csv"), "id");
boolean workNow = hasCsvFiles(shared);                     // true

For rules a glob cannot express, the overload newDirectoryStream(dir, filter) takes a DirectoryStream.Filter, for example entry -> !entry.getFileName().toString().startsWith(“.”) to skip every dot file.

5. Why File.list() Is Slower for Large Folders

The java.io.File methods list() and listFiles() read every name in the folder into an array, so the cost grows with the folder size. They also return null instead of throwing when the path is not a readable folder, and code that checks only the length fails with NullPointerException.

File folder = Files.createTempDirectory("legacy").toFile();
String[] names = folder.list();
boolean empty = names != null && names.length == 0;        // true
String[] fromFile = new File(folder, "missing").list();    // null, not an exception

For small folders the difference does not matter, but in new code Files.list() gives both the lazy read and a clear exception. A File from older code converts with toPath().

6. Empty Directory vs Empty File

An empty file is a different check. A file is empty when its size is zero bytes, which Files.size() tells us without reading the content. Calling it on a folder returns a size that depends on the file system, so we test the type first.

Path dir = Files.createTempDirectory("files");
Path blank = Files.createFile(dir.resolve("blank.txt"));
Path notes = Files.writeString(dir.resolve("notes.txt"), "buy milk");
boolean blankEmpty = Files.isRegularFile(blank) && Files.size(blank) == 0;   // true
boolean notesEmpty = Files.isRegularFile(notes) && Files.size(notes) == 0;   // false

A file that contains only a line break has a size of one byte, so code that treats whitespace as empty reads the content with Files.readString() and calls isBlank().

7. Finding Empty Subfolders in a Tree

After a job moves processed files to an archive, it often leaves empty date folders behind. We find them with Files.walk(), keep the folders and test each one with the isEmpty() method from section 1.

static List<Path> emptyFolders(Path root) throws IOException {
    try (Stream<Path> tree = Files.walk(root)) {
        List<Path> result = new ArrayList<>();
        for (Path path : tree.filter(Files::isDirectory).toList()) {
            if (isEmpty(path)) {
                result.add(root.relativize(path));
            }
        }
        result.sort(Comparator.naturalOrder());
        return result;
    }
}
Path archive = Files.createTempDirectory("archive");
Path oct = Files.createDirectories(archive.resolve("2026/10"));
Path nov = Files.createDirectories(archive.resolve("2026/11"));
Path kept = Files.writeString(oct.resolve("orders.csv"), "x");
List<Path> leftovers = emptyFolders(archive);              // [2026/11]

Deleting 2026/11 can make 2026 empty in turn, so a cleanup that removes whole empty branches deletes in reverse order, the same way as deleting a directory recursively.

8. Empty Directory Check FAQs

The emptiness check is short, yet it leaves doubts about huge folders, files that arrive a moment later, library support and waiting for new files.

8.1. Is Files.list() faster than File.list() for large directories?

Yes, for an emptiness check. Files.list() with findAny() reads one entry and stops, while File.list() reads every name into an array first. For a folder with hundreds of thousands of files, that is the difference between one entry and all of them in memory.

8.2. Can a directory become non-empty right after the check?

Yes. Another process can add a file a moment later, so the result is a snapshot. Code that deletes a folder after an empty check uses Files.delete(), which throws DirectoryNotEmptyException if a file appeared in between.

8.3. Does Commons IO have a method for this?

Yes. Commons IO has PathUtils.isEmptyDirectory(path) and FileUtils.isEmptyDirectory(file), which use a directory stream internally. For a single check, the JDK methods in section 1 are short enough that we don’t need the dependency.

8.4. How do we wait until a directory receives a file?

Instead of checking in a loop, we register the folder with a WatchService and react to ENTRY_CREATE events. A single empty check at startup still covers files that arrived while the app was down.

9. Conclusion

Files.newDirectoryStream() with iterator().hasNext() and Files.list() with findAny() check whether a directory is empty by reading at most one entry, and both need try-with-resources to release the directory handle. They throw for files and missing paths, so we either let that fail loudly or check Files.isDirectory() first.

Hidden files such as .DS_Store count as entries, and a glob or filter limits the check to the files our code processes. File.list() still works for small folders but loads every name and returns null on errors. The Java IO tutorial collects the other folder operations, such as copying and watching.

10. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.