Files.write(Paths.get("image.png"), bytes); (1)
List<String> lines = Files.readAllLines(Paths.get("letter.txt"), StandardCharsets.UTF_8); (2)
Files.lines(Paths.get("letter.txt"), StandardCharsets.UTF_8)
.forEach(System.out::println);
Java File vs Path
2017-09-02 java
I’ve been using java.io.File and java.io.File*Stream since Java 1.1, a long time ago.
Java 7 introduced a new file API named NIO2 containing, among others, the java.nio.file.Path and java.nio.file.Files classes.
It took me a while to lose my habits and embrace the new API.
Spoiler: The most funny part of this article is at the end!
Quick comparison
| java.io.File (class) | java.nio.file.Path (interface) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Some additional notes:
-
PaththrowsIOExceptionmore often thanFile, and rarely return abooleanto tell if something was done (mkdirs(),delete()) -
Fileis more object oriented thanPath: I regret thatsize(),exists()… methods are not on thePathinterface. This is probably due to the fact that this API was added in Java 7, but default methods on interfaces were added later in Java 8. -
PathbasedInputStream/`OutputStream`s are less expensive from a GC point view. Thanks @kittster for mentionning this article from Cloudbees.
One liners
java.nio.file.Files allows to read, write, copy files in a single line:
| 1 | Write a binary file |
| 2 | Read a text file |
This nearly makes Guava IO and Commons IO useless. I regret that there isn’t any method out of the box to read/write a whole file as a single string.
Many APIs (JAXB, Jackson to name a few) don’t use Path`s to read/write files, the workaround is usually use an `InputStream or an OutputStream.
try(InputStream inputStream = Files.newInputStream(path)) {
Thing thing = (Thing) unmarshaller.unmarshal(inputStream);
}
Multiple file systems
When the File is only for local files, Path can also be used to access remote files.
A Path is associated to a FileSystem.
To create a new Path instances, there is not constructor (Path is interface), we need to call a factory method. The above 2 lines are the same:
path = Paths.get("path/to/file.txt");
path = FileSystems.getDefault().getPath("path/to/file.txt");
As the default file system is the local one, you get a path to a local file.
Depending on the underlying file system, you’ll get a different implementation: sun.nio.fs.UnixPath, sun.nio.fs.WindowsPath…
With this trick in mind, we can read the content of a Zip file, as if we had extracted it:
URI zipUri = new URI("jar:file:/path/to/archive.zip")
try(FileSystem zipFS = FileSystems.newFileSystem(zipUri, emptyMap())) { (1)
Path zipPath = zipFS.getPath("/archive") (2)
Files.list(zipPath)
.map(Path::toString)
.forEach(System.out::println);
}
| 1 | "Mount" the Zip file as a file system |
| 2 | zipPath is of type com.sun.nio.zipfs.ZipPath |
Other posts
- 2020-11-28 Build your own CA with Ansible
- 2020-01-16 Retrieving Kafka Lag
- 2020-01-10 Home temperature monitoring
- 2019-12-10 Kafka connect plugin install
- 2019-07-03 Kafka integration tests