1. Introduction
FileNotFoundException is a common checked exception when we work with files in Java.
In this tutorial, weβll discuss when FileNotFoundException can occur and common ways of handling it through examples.
2. When Is the Exception Thrown?
As indicated in Javaβs API documentation, FileNotFoundException can be thrown when:
- We try to access a non-existent file
- The file exists but is inaccessible for some reason, for example, attempting to write to a read-only file
Next, letβs see some examples.
For simplicity, weβll use JUnit 5 and itβs temporary directory support for demonstrations in this tutorial.
2.1. When a File Doesnβt Exist
Letβs first create a Path instance with the @TempDir annotation, which will be used as the root temporary directory for all tests:
@TempDir
private Path tempDir;
Next, letβs try to access a non-existent file and see what will happen:
File notExistFile = tempDir.resolve("dummy.notExist").toFile();
assertThrows(FileNotFoundException.class, () -> {FileReader fileReader = new FileReader(notExistFile);});
As the example shows, we created a FileReader object on notExistFile. As a result, FileNotFoundException was thrown.
2.2. When a File Is Inaccessible
Now, letβs see what happens if we attempt to write to a read-only file:
File readOnlyFile = tempDir.resolve("dummy.ReadOnly").toFile();
// first creating a read-only file
try (PrintWriter printWriter = new PrintWriter(new FileWriter(readOnlyFile))) {
printWriter.println("Hi there!");
readOnlyFile.setReadOnly();
}
assertTrue(readOnlyFile.exists());
assertFalse(readOnlyFile.canWrite());
// now we create a FileWriter on the read-only file
assertThrows(FileNotFoundException.class, () -> {
FileWriter fileWriter = new FileWriter(readOnlyFile);
});
As the code above shows, we first created a readOnlyFile with some content (βHi there!β) using try-with-resources. Then, FileNotFoundException was raised when we tried to instantiate a FileWriter instance on the read-only file.
3. Handling FileNotFoundException
In this section, weβll show some common approaches to handling a FileNotFoundException in Java.
3.1. Log the Exception When It Occurs
Sometimes, when a FileNotFoundException isnβt a critical error, it shouldnβt stop the execution. In this case, we may want to log it for further analysis:
Path notExistFile = tempDir.resolve("dummy.notExist");
try {
FileReader fileReader = new FileReader(notExistFile.toFile());
} catch (FileNotFoundException ex) {
LOG.warn("Error Occurred when reading the optional file " + notExistFile, ex);
}
When we execute this code, we see the following output:
[2024-09-04 15:19:55,069]-[main] WARN ... - Error Occurred when reading the optional file /path/to/dummy.notExist
java.io.FileNotFoundException: /path/to/dummy.notExist (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
...
In this example, we log the FileNotFoundExcetion as a βwarningβ with a meaningful message.
3.2. Raising a Custom Exception
Sometimes, when a FileNotFoundException occurs, we must stop the current execution. However, we want to wrap it in a customer exception and leave this decision to the upper layers of the application.
Letβs first create a ConfiguraionException class:
class ConfigurationException extends RuntimeException {
ConfigurationException(String string, FileNotFoundException ex) {
super(string, ex);
}
}
Next, letβs create a method that reads some configurations from a file:
String readConfig(Path path) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(path.toFile()))){
return reader.readLine();
} catch (FileNotFoundException ex) {
throw new ConfigurationException("Reading configuration file failed", ex);
}
}
As we can see, if we encounter FileNotFoundException, we wrap it in our ConfigurationException and ask the caller to decide how to deal with this case β for example, creating a new configuration file or using some default configurations:
assertThrows(ConfigurationException.class, () -> readConfig(tempDir.resolve("dummy.notExist")));
The above test shows that readConfig() throws ConfigurationException when we pass a non-existent file to it.
3.3. With Some Recovery Actions
In some cases, we might want to perform some recovery actions when the exception occurs. Letβs see an example:
public String readOrCreateFileWithContent(Path path, String defaultValue) {
try (BufferedReader reader = new BufferedReader(new FileReader(path.toFile()))) {
return reader.readLine();
} catch (FileNotFoundException e) {
try (PrintWriter writer = new PrintWriter(new FileWriter(path.toFile()))) {
writer.print(defaultValue);
return defaultValue;
} catch (IOException ex) {
throw new RuntimeException("IOException when trying to create the file", ex);
}
} catch (IOException e) {
throw new RuntimeException("IOException when trying to read the file", e);
}
}
As the method shows, we first try to read a line from the desired file. If the file doesnβt exist, we create a file with the given path and write defaultValue to it as a recovery:
Path path = tempDir.resolve("dummy.notExist");
assertFalse(path.toFile().exists()); // file doesn't exist
String defaultValue = "the-default-value";
String value = readOrCreateFileWithContent(path, defaultValue);
assertEquals(defaultValue, value);
assertEquals(defaultValue, Files.readString(path));
In this test, we call readOrCreateFileWithContent() by passing a non-existent file path. As a result, the file is automatically created with defaultValue as its content.
4. Conclusion
In this article, weβve discussed when a FileNotFoundException can occur and explored several common approaches to handle this exception.
