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:
-
Path
throwsIOException
more often thanFile
, and rarely return aboolean
to tell if something was done (mkdirs()
,delete()
) -
File
is more object oriented thanPath
: I regret thatsize()
,exists()
… methods are not on thePath
interface. 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. -
Path
basedInputStream
/`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