I'm trying to find an easy way to map a URI
to a Path
without writing code specific to any particular file system. The following seems to work but requires a questionable technique:
public void process(URI uri) throws IOException {
try {
// First try getting a path via existing file systems. (default fs)
Path path = Paths.get(uri);
doSomething(uri, path);
}
catch (FileSystemNotFoundException e) {
// No existing file system, so try creating one. (jars, zips, etc.)
Map<String, ?> env = Collections.emptyMap();
try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {
Path path = fs.provider().getPath(uri); // yuck :(
// assert path.getFileSystem() == fs;
doSomething(uri, path);
}
}
}
private void doSomething(URI uri, Path path) {
FileSystem fs = path.getFileSystem();
System.out.println(uri);
System.out.println("[" + fs.getClass().getSimpleName() + "] " + path);
}
Running this code on a couple examples produces the following:
file:/C:/Users/cambecc/target/classes/org/foo
[WindowsFileSystem] C:\Users\cambecc\target\classes\org\foo
jar:file:/C:/Users/cambecc/bin/utils-1.0.jar!/org/foo
[ZipFileSystem] /org/foo
Notice how the URI
s have been mapped to Path
objects that have been "rooted" into the right kind of FileSystem
, like the Path referring to the directory "/org/foo" inside a jar.
What bothers me about this code is that although NIO2 makes it easy to:
- map a URI to a Path in existing file systems:
Paths.get(URI)
- map a URI to a new
FileSystem
instance:FileSystems.newFileSystem(uri, env)
... there is no nice way to map a URI to a Path in a new FileSystem
instance.
The best I could find was, after creating a FileSystem, I can ask its FileSystemProvider
to give me Path:
Path path = fs.provider().getPath(uri);
But this seems wrong as there is no guarantee it will return a Path that is bound to the FileSystem that I just instantiated (i.e., path.getFileSystem() == fs
). It's pretty much relying on the internal state of FileSystemProvider to know what FileSystem instance I'm referring to. Is there no better way?
FileSystems.newFileSystem
makes sense. Creating a new zipfs means opening the underlying zip file, a file that must eventually be closed. This is whyFileSystem
implementsCloseable
. So the reasonPaths.get(uri)
does not automatically open a zipfs is because the designers wanted the opening and closing of the zipfsFileSystem
object to be explicitly done by the programmer. At least, that's my conjecture. :) That's why I used try-with-resources in my sample code above. – Preamplifier