La solution la plus générale est la suivante:
interface IOConsumer<T> {
void accept(T t) throws IOException;
}
public static void processRessource(URI uri, IOConsumer<Path> action) throws IOException {
try {
Path p=Paths.get(uri);
action.accept(p);
}
catch(FileSystemNotFoundException ex) {
try(FileSystem fs = FileSystems.newFileSystem(
uri, Collections.<String,Object>emptyMap())) {
Path p = fs.provider().getPath(uri);
action.accept(p);
}
}
}
Le principal obstacle est de gérer les deux possibilités, soit d'avoir un système de fichiers existant que nous devrions utiliser, mais pas de fermer (comme avec les file
URI ou le stockage de modules de Java 9), soit d'avoir à ouvrir et donc fermer en toute sécurité le système de fichiers nous-mêmes (comme zip / jar).
Par conséquent, la solution ci-dessus encapsule l'action réelle dans un interface
, gère les deux cas, se fermant ensuite en toute sécurité dans le second cas, et fonctionne de Java 7 à Java 10. Elle vérifie s'il existe déjà un système de fichiers ouvert avant d'en ouvrir un nouveau, donc il fonctionne également dans le cas où un autre composant de votre application a déjà ouvert un système de fichiers pour le même fichier zip / jar.
Il peut être utilisé dans toutes les versions de Java nommées ci-dessus, par exemple pour lister le contenu d'un paquet ( java.lang
dans l'exemple) en tant que Path
s, comme ceci:
processRessource(Object.class.getResource("Object.class").toURI(), new IOConsumer<Path>() {
public void accept(Path path) throws IOException {
try(DirectoryStream<Path> ds = Files.newDirectoryStream(path.getParent())) {
for(Path p: ds)
System.out.println(p);
}
}
});
Avec Java 8 ou plus récent, vous pouvez utiliser des expressions lambda ou des références de méthode pour représenter l'action réelle, par exemple
processRessource(Object.class.getResource("Object.class").toURI(), path -> {
try(Stream<Path> stream = Files.list(path.getParent())) {
stream.forEach(System.out::println);
}
});
Faire la même chose.
La version finale du système de modules de Java 9 a cassé l'exemple de code ci-dessus. Le JRE renvoie de manière incohérente le chemin /java.base/java/lang/Object.class
pour Object.class.getResource("Object.class")
alors qu'il devrait l'être /modules/java.base/java/lang/Object.class
. Cela peut être résolu en ajoutant les éléments manquants /modules/
lorsque le chemin parent est signalé comme inexistant:
processRessource(Object.class.getResource("Object.class").toURI(), path -> {
Path p = path.getParent();
if(!Files.exists(p))
p = p.resolve("/modules").resolve(p.getRoot().relativize(p));
try(Stream<Path> stream = Files.list(p)) {
stream.forEach(System.out::println);
}
});
Ensuite, il fonctionnera à nouveau avec toutes les versions et méthodes de stockage.
Paths.get(URI)
, alors ´URL.toURI (), and last
getResource () `qui retourne unURL
. Vous pourrez peut-être les enchaîner. Je n'ai pas essayé cependant.