Paths and files in Java

Paths and files in Java #

Java’s initial package for input/output (I/O) is called java.io. A central class in this package is File.

Over the years, programmers realized that this package had limitations: limited error handling, limited support for file metadata (owner, access rights, etc.), and some performance issues.

With Java 7 (2011), A new I/O package called NIO2 was released, with additional features (and in some cases a more concise syntax). A central interface (resp. utility class) in this package is Path (resp. Files).

However, the package java.io is still part of the latest Java release (it has not been deprecated), in part for backward compatibility reasons.

In this chapter, we will focus whenever possible on NIO2’s classes and methods, rather than java.io. In particular, we will use Path when possible rather than File.

Note also that some external libraries (notably Apache commons.io and Guava) provide additional methods for I/O, sometimes with a more concise syntax.

Warning. Many native Java methods that involve path or file manipulation may throw a checked exception (generally an IOException). For instance, among the methods below, this is the case of:

  • Path.toRealPath,
  • Files.size,
  • Files.walk,
  • etc.

As a reminder, when such a method is used, checked exceptions must be either caught or explicitly rethrown, otherwise the program will not compile.

Paths #

An instance of Path represents a path in the hierarchical file system.

An instance of Path can be created in multiple ways. For instance:

Path myPath = Path.of("path/to/file.txt");
Path samePath = Path.of("path", "to", "file.txt");

// Extend a path
Path folder = Path.of("path/to");
// identical to myPath
Path myPathAgain = folder.resolve("file.txt");

Path names #

Note. If the string path/to/file.txt is used to create a Java Path (or a Java File), then the / symbol is interpreted (at runtime) as the path separator of the operating system (OS) that executes the program. So you can safely use this syntax, regardless of your OS. Precisely:

  • if the program is executed on macOS, Linux, Android, etc., then this string will be interpreted as is,
  • if the program is executed on Windows, then this string will be interpreted as path\to\file.txt.

Warning. If the string path\to\file.txt is used to create a Java Path, then this string will be interpreted as is. So the program may run on Windows, but fail on other systems.

Warning. Paths are case-sensitive (by default) on Linux, Android, etc., but case insensitive (by default) on Windows and macOS. For maximal compatibility, make sure that path names in your code respect the case of your file and directory names.

Warning. Do not use absolute paths in your code (e.g. /home/alice/workspace/javaProject/myFile.txt, or C:\Users\alice\workspace\javaProject\myFile.txt). Your program may run on your own computer, but will fail on others.

Working directory #

Warning. When a Java program is executed, relative paths are understood as paths from the current working directory (WD).

If you need to know the WD, you can use the following (among other possibilities):

Paths.get("").toAbsolutePath();

This instruction returns an absolute Path to the WD.

For instance,

System.out.println(Paths.get("").toAbsolutePath());

may output on Windows:

C:\Users\alice\workspace\javaProject

or on macOS:

/Users/alice/workspace/javaProject

or on Linux:

/home/alice/workspace/javaProject

The Path interface #

Here are examples of outputs for some methods of the Path interface (assuming that the WD is /home/alice/workspace/javaProject):

Path path = Path.of("src/main/../main/resources/myFile.txt");

// Outputs '/home/alice/workspace/javaProject/src/main/../main/resources/myFile.txt'
System.out.println(path.toAbsolutePath());

// Outputs '/home/alice/workspace/javaProject/src/main/resources/myFile.txt'
System.out.println(path.toRealPath());

// Outputs 'myFile.txt'
System.out.println(path.getFileName());

// Outputs 'false'
System.out.println(path.isAbsolute());

Hint. The method String.endsWith can be used to check whether a file has a certain extension. E.g.

// Outputs 'true'
path.toString().endsWith(".txt");

Existence and metadata #

Static methods of the class Files can be used to check whether a file or directory exists, and retrieve metadata about it:

Path path = Path.of("src/main/resources/myFile.txt");

System.out.println("Exists = " + Files.exists(path));
System.out.println("Is directory = " + Files.isDirectory(path));
System.out.println("Is file = " + Files.isRegularFile(path));
System.out.println("Is hidden = " + Files.isHidden(path));
System.out.println("Size = " + Files.size(path) + " bytes");
System.out.println("Last modified = " + Files.getLastModifiedTime(path));
Path path = Path.of("src/main/resources/myFile.txt");

// Get the parent directory 'src/main/resources'
Path dir = path.getParent();

// Contains all files and folders in 'src/main/resources'
List<Path> children = Files.list(dir).toList();

// Contains all files and folders that have 'src/main/resources'
// as ancestor, including 'src/main/resources' itself.
List<Path> descendents = Files.walk(dir).toList();

Manipulation #

// Create a directory
Path folder = Path.of("myFolder");
Files.createDirectory(folder);

// Create nested directories
Path subfolder = Path.of("myFolder/sub1/sub2");
Files.createDirectories(subfolder);

// Create a file
Path file = Path.of("myFolder/hello.txt");
Files.createFile(file);

// Move/rename a file
Path destination = Path.of("myFolder/sub1/bye.txt");
Files.move(file, destination);

// Copy a file
Path copy = Path.of("myFolder/sub1/sub2/bybye.txt");
Files.copy(renamedFile, copy);

// Delete a file.
Files.delete(copy);

// Delete a directory.
// The directory must be empty.
Files.delete(subfolder);