Java : Don't use the legacy File class, use new I/O APIs instead
The File class is legacy. It has several drawbacks. In this article, I will introduce you to problems of the File class and the new APIs that replace it.
Note:
- This article may use translation software for your convenience. Please also check the original Japanese version.
Introduction
The File class is a traditional class that has existed since Java 1. If you have been using Java for a long time, you may have used it. Java 7 added new APIs of File I/O to a java.nio.file package. The new APIs include the Path interface and the Files class.
This article recommends using the new I/O APIs instead of the File class.
File class problems
The File API documentation says that the java.nio.file package (i.e. the Path interface and the Files class) may be used to overcome many of the limitations of the File class.
The Java Tutorials documentation says more specific about the problems. I'm just quoting some of the problems. Please check the link for details.
Now let's actually check the code example.
An example of the File class.
// --- PowerShell ---
//PS R:\java-work> tree /F
//
//R:.
//├─empty-dir
//└─non-empty-dir
// aaa.txt
final var emptyDir = new File("R:\\java-work\\empty-dir");
System.out.println(emptyDir.delete()); // true
final var nonEmptyDir = new File("R:\\java-work\\non-empty-dir");
System.out.println(nonEmptyDir.delete()); // false
final var nonExistentDir = new File("R:\\java-work\\XXX");
System.out.println(nonExistentDir.delete()); // false
// --- PowerShell ---
//PS R:\java-work> tree /F
//
//R:.
//└─non-empty-dir
// aaa.txt
The File.delete method returns false if the operation fails. In the code example, the 2nd and 3rd failed. But the program can not know why it failed if it's just returned false.
Next, an example of the Path interface and the Files class.
// --- PowerShell ---
//PS R:\java-work> tree /F
//
//R:.
//├─empty-dir
//└─non-empty-dir
// aaa.txt
//----------
// OK
final var emptyDir = Path.of("R:", "java-work", "empty-dir");
Files.delete(emptyDir);
//----------
// NG
try {
final var nonEmptyDir = Path.of("R:", "java-work", "non-empty-dir");
Files.delete(nonEmptyDir);
} catch (IOException e) {
System.out.println(e);
}
// Result
// ↓
// java.nio.file.DirectoryNotEmptyException: R:\java-work\non-empty-dir
//----------
// NG
try {
final var nonExistentDir = Path.of("R:", "java-work", "XXX");
Files.delete(nonExistentDir);
} catch (IOException e) {
System.out.println(e);
}
// Result
// ↓
// java.nio.file.NoSuchFileException: R:\java-work\XXX
// --- PowerShell ---
//PS R:\java-work> tree /F
//
//R:.
//└─non-empty-dir
// aaa.txt
The Files class throws an IOException (or its subclass) if the operation fails. In the code example, throw the DirectoryNotEmptyException and the NoSuchFileException. The program could know why it failed.
Path interface, Files class advantage
The problems of the File class are resolved with the Path interface and the Files class. There are other benefits as well.
Let's look at the role of each APIs.
API | Role |
---|---|
File | - has a path name. - operates the path name. (getName, getParent etc.) - accesses files. (mkdir, exists, delete etc.) |
Path | - has a path name. - operates the path name. (getName, getParent etc.) |
Files | - accesses files. (createDirectory, exists, delete etc.) |
It is an image of dividing the role of the File class into two.
To access files is one of the most sensitive things in a program. It would be a big problem if the user's important files were deleted by mistake...
With the File class, even code that only needs to operate the path name must be careful not to access files. In such a case, it is safe to use the Path interface. Because your code doesn't access files unless you use the Files class.
Note
- The Path interface has some methods that cause an IOException, such as the toRealPath method and the register method.
Interoperability
Some older APIs may require the legacy File class as a parameter. It's okay when it's like that. APIs are provided for interoperability.
final Path path = Path.of("sample.txt");
final File file = path.toFile();
System.out.println(file); // sample.txt
final File file = new File("sample.txt");
final Path path = file.toPath();
System.out.println(path); // sample.txt
Conclusion
The File class is legacy. It has several drawbacks. It is better to use the Path interface and the Files class instead.