1. Methods for checking the existence of files and directories
Working with files can feel like a walk through a minefield: you never know what awaits you beyond the next byte. The good news: Java gives us a “metal detector” — methods to check for the existence of files and folders.
The File class: checking via exists(), isFile(), isDirectory()
A classic way is to use the java.io.File class:
File file = new File("example.txt");
if (file.exists()) {
System.out.println("File exists!");
} else {
System.out.println("File not found.");
}
The exists() method returns true if a file or folder with that name exists. But that’s not all! Sometimes you need to know exactly what exists: a file or a directory.
if (file.isFile()) {
System.out.println("This is a file.");
} else if (file.isDirectory()) {
System.out.println("This is a directory.");
} else {
System.out.println("Nothing found.");
}
The Path and Files classes: the modern approach
In modern code, it’s better to use the newer and more powerful java.nio.file API. Here, the static method Files.exists() is used to check for existence:
import java.nio.file.*;
Path path = Paths.get("example.txt");
if (Files.exists(path)) {
System.out.println("File found via NIO!");
}
To check the object type, use:
if (Files.isRegularFile(path)) {
System.out.println("This is a regular file!");
}
if (Files.isDirectory(path)) {
System.out.println("This is a directory!");
}
Tip: for new projects, prefer NIO (Path, Files) right away because this API is more modern, supports more features, and plays nicely with try-with-resources.
Table: comparing the approaches
| Approach | Existence check | Type check (file/folder) | Modernity |
|---|---|---|---|
|
Yes | Yes (isFile(), isDirectory()) | Legacy |
|
Yes | Yes (isRegularFile(), isDirectory()) | Recommended |
2. The TOCTOU problem: why checking is not a silver bullet
What’s the issue?
Suppose you checked: “File exists!” — and immediately decided to read it. But between these two actions an eternity can pass in CPU terms. During that time the file can be deleted, moved, replaced by another process, or its permissions can change.
It’s like peeking into the fridge, noting there’s cake, closing the door, and then opening it again — only to find the cake has been eaten. Programming has such “housemates,” too: other processes, users, antivirus tools, and the file system itself.
Why does this matter?
As a result, even if you checked that the file exists, trying to open it can still throw an exception — for example, FileNotFoundException or AccessDeniedException.
So a check is not a guarantee; it’s only an extra safety net. Always be prepared for exceptions and handle them!
3. Practice: check for a file before reading
Let’s add a function that prints a file’s contents if it exists, and informs the user if it does not. We’ll show two variants: via the old and the new API.
Option 1: via File
import java.io.*;
public class FileExistenceCheck {
public static void main(String[] args) {
File file = new File("notes.txt");
if (file.exists() && file.isFile()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
} else {
System.out.println("File 'notes.txt' not found.");
}
}
}
Option 2: via Path and Files
import java.nio.file.*;
import java.io.IOException;
public class PathExistenceCheck {
public static void main(String[] args) {
Path path = Paths.get("notes.txt");
if (Files.exists(path) && Files.isRegularFile(path)) {
try {
Files.lines(path).forEach(System.out::println);
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
} else {
System.out.println("File 'notes.txt' not found.");
}
}
}
Even after checking — catch exceptions!
In both examples, despite the preliminary check, we still use try–catch blocks, because a file can disappear or become inaccessible at any moment. This is the golden rule of working with files!
4. Checking for a directory’s existence
Similarly, you can check whether a folder exists and create it if it doesn’t:
import java.nio.file.*;
public class DirectoryCheck {
public static void main(String[] args) {
Path dir = Paths.get("data");
if (Files.exists(dir) && Files.isDirectory(dir)) {
System.out.println("Directory 'data' found.");
} else {
System.out.println("Directory 'data' not found. Creating...");
try {
Files.createDirectory(dir);
System.out.println("Directory created!");
} catch (IOException e) {
System.out.println("Error creating directory: " + e.getMessage());
}
}
}
}
By the way:
The Files.createDirectory() method throws an exception if the directory already exists. If you want to create a chain of directories (for example, "data/2025/09"), use Files.createDirectories(), which won’t complain if some of the directories already exist.
5. Details and gotchas: relative and absolute paths
Relative paths
When you write "notes.txt", the program looks for the file in the “current working directory.” Where that is depends on how and from where you run the application (IDE, terminal, double-clicking a JAR, etc.).
Absolute paths
If you need to be sure where to look, it’s better to use absolute paths or build them dynamically:
String userHome = System.getProperty("user.home");
Path filePath = Paths.get(userHome, "myapp", "notes.txt");
Checking the object’s type
Sometimes a “file” can unexpectedly turn out to be a directory. Therefore, check not only existence but also the type:
if (Files.isRegularFile(path)) {
// This is a file!
}
if (Files.isDirectory(path)) {
// This is a directory!
}
6. Demonstrating TOCTOU in practice
Let’s simulate a situation where the file disappears after the check but before opening. Run the code and delete the file manually between the check and the read:
import java.io.*;
import java.nio.file.*;
public class TOCTOUExample {
public static void main(String[] args) {
Path path = Paths.get("notes.txt");
if (Files.exists(path)) {
System.out.println("File found, starting to read...");
// At this point, open your file explorer and delete "notes.txt" manually!
try {
Files.lines(path).forEach(System.out::println);
} catch (IOException e) {
System.out.println("Oops! The file disappeared: " + e.getMessage());
}
} else {
System.out.println("File not found.");
}
}
}
Result:
If you manage to delete the file between the check and the read, you’ll get an exception. This clearly shows that even a careful check doesn’t protect you from unexpected changes.
7. Common mistakes when checking for files and folders
Mistake #1: Relying only on a check and not using try-catch. “If the file exists, it’s safe to read it,” beginners think. But the file can disappear or become inaccessible, and your program will crash.
Mistake #2: Checking only existence, not the type. If you check only exists() without clarifying whether it’s a file or a directory, you can try to open a directory as a file — and get an error.
Mistake #3: Using relative paths without understanding the working directory. The program looks for the file “in the wrong place,” and the user can’t understand why nothing works.
Mistake #4: Ignoring permissions. A file or folder can exist, but you may lack read/write permissions. Such issues surface only when you try to open the file — always use try–catch.
Mistake #5: Ignoring case sensitivity across operating systems. On Windows, file names are case-insensitive, while on Linux they are case-sensitive. A program may not find "Notes.txt" if it’s looking for "notes.txt".
GO TO FULL VERSION