1. Recap: File vs Path vs Files
Good old File
Yes... there is plenty of legacy code in Java projects. So let’s once again recall the veteran of Java, the File class. It appeared in the language back in version 1.0 and lets you work with files and folders: find out whether a file exists, its name, size, modification date; create and delete files and folders. As we already know, it has plenty of drawbacks: some methods behave unintuitively, not all operations are cross-platform, and some methods return just false instead of throwing exceptions (which isn’t always convenient for debugging).
import java.io.File;
File file = new File("example.txt");
System.out.println("Does the file exist? " + file.exists());
System.out.println("Is it a file? " + file.isFile());
System.out.println("Is it a directory? " + file.isDirectory());
Path and Files: a modern take (Java 7+)
With the release of Java 7, the java.nio.file package arrived, offering more powerful and flexible tools. Two key players:
- Path — an interface that represents a path to a file or folder. You could say it’s “a string with brains”: it can parse, join, analyze, and compare paths.
- Files — a utility class with a bunch of static methods for working with files and directories: creation, deletion, copying, reading, writing, and retrieving information.
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
System.out.println("Path: " + path);
Fun fact: the Path class is not just a string! It knows about directory separators, can parse relative and absolute paths, and works equally well on Windows and Linux.
Comparison of File and Path/Files
| Criterion | File (legacy API) | Path + Files (modern API) |
|---|---|---|
| Syntax | OOP style | Combination of Path + static methods in Files |
| Cross-platform support | Partial | Excellent, OS-aware |
| Exceptions | Not always | Almost always |
| New capabilities | No | Yes (attributes, permissions, links, etc.) |
| Recommended | Generally no | Yes |
2. Retrieving information about a file/directory
Let’s figure out how to get the most important information about a file or folder: whether the object exists, its type (file or directory), size, name, path, and parent directory.
Checking existence
Via File
File file = new File("example.txt");
if (file.exists()) {
System.out.println("File exists!");
} else {
System.out.println("File not found.");
}
Via Path and Files
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
if (Files.exists(path)) {
System.out.println("File exists!");
} else {
System.out.println("File not found.");
}
Tip: For new projects always use Path and Files. It’s safer, more convenient, and cross-platform.
Type check: file or directory
File
if (file.isFile()) {
System.out.println("This is a file.");
} else if (file.isDirectory()) {
System.out.println("This is a directory.");
}
Path + Files
if (Files.isRegularFile(path)) {
System.out.println("This is a file.");
} else if (Files.isDirectory(path)) {
System.out.println("This is a directory.");
}
Getting the file size
File
long size = file.length();
System.out.println("File size: " + size + " bytes");
Path + Files
try {
long size = Files.size(path);
System.out.println("File size: " + size + " bytes");
} catch (IOException e) {
System.out.println("Error getting file size: " + e.getMessage());
}
Note: For a directory, length() always returns 0, and Files.size(path) throws an IOException. A directory’s size is the sum of the sizes of all files inside (more on this in the following lectures).
Getting the absolute and relative path
File
System.out.println("Relative path: " + file.getPath());
System.out.println("Absolute path: " + file.getAbsolutePath());
Path
System.out.println("Relative path: " + path);
System.out.println("Absolute path: " + path.toAbsolutePath());
Getting the file name and parent directory
File
System.out.println("File name: " + file.getName());
System.out.println("Parent directory: " + file.getParent());
Path
System.out.println("File name: " + path.getFileName());
System.out.println("Parent directory: " + path.getParent());
Pro tip: Path can work not only with files but also with directories, relative and absolute paths, and can easily split a path into parts.
3. Retrieving file attributes
Sometimes you want to know not only the size and the name of a file, but also something more interesting: creation time, last modification time, access permissions.
Creation and last modification dates
File (limited)
long lastModified = file.lastModified();
System.out.println("Last modified: " + new java.util.Date(lastModified));
Downside: You cannot get the file creation time via File!
Path + Files
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
FileTime creationTime = attrs.creationTime();
FileTime lastModifiedTime = attrs.lastModifiedTime();
System.out.println("Creation time: " + creationTime);
System.out.println("Last modified time: " + lastModifiedTime);
} catch (IOException e) {
System.out.println("Error getting attributes: " + e.getMessage());
}
Checking access permissions
File
System.out.println("Readable? " + file.canRead());
System.out.println("Writable? " + file.canWrite());
System.out.println("Executable? " + file.canExecute());
Path + Files
System.out.println("Readable? " + Files.isReadable(path));
System.out.println("Writable? " + Files.isWritable(path));
System.out.println("Executable? " + Files.isExecutable(path));
Fun fact: On Windows, access rights are limited, whereas on Unix systems you can get and change many more (for example, via POSIX attributes).
4. Common mistakes when retrieving file information
Error #1: Using File when you need Path.
Many beginners keep using File because it seems simpler or “that’s how it’s done on the internet.” But with Path and Files you can do the same things, only more reliably and in a more modern way.
Error #2: Checking the object type only via File.
If you use only file.isFile() and file.isDirectory(), you may miss “special” files (symbolic links, devices). In the modern API there are Files.isRegularFile(path), Files.isDirectory(path), and other checks.
Error #3: Ignoring exceptions.
The methods Files.size(path) and Files.readAttributes(...) throw IOException. If you don’t handle exceptions, the program will crash on the first access error or if a file disappears while your program is running.
Error #4: Expecting that you can get a directory’s size directly.
The method Files.size(path) will throw an exception for a directory. To get a directory’s size, you need to recursively sum the sizes of all files inside.
Error #5: Insufficient permission checks.
Even if a file exists, you might not have read or write permissions. Always check permissions before operations: Files.isReadable(path), Files.isWritable(path), Files.isExecutable(path).
GO TO FULL VERSION