'get FileSystems of a jar inside another jar
This is what I'm trying to do:
FileSystem fs1 = FileSystems.newFileSystem(Paths.get("f1.jar"), null);
FileSystem fs2 = FileSystems.newFileSystem(fs1.getPath("/f2.jar"), null);
but I get a java.nio.file.ProviderNotFoundException thrown by FileSystems.newFileSystem() on the second line.
What am I doing wrong?
Thanks!
Solution 1:[1]
Given a jarfile URI like: jar:file:/console/console.jar!/BOOT-INF/lib/generator.jar!/generator/static/
I wrote the following method to extract the jars recursively and return all of the file systems:
private FileSystem getNestedFileSystems(URI generatorAssets) throws IOException {
String[] jarFiles = generatorAssets.toString().split("!");
URI rootJarUri = URI.create(jarFiles[0]);
FileSystem currentFs;
try {
currentFs = FileSystems.getFileSystem(rootJarUri);
} catch (FileSystemNotFoundException fsnf) {
currentFs = FileSystems.newFileSystem(rootJarUri, Map.of("create", "true"));
}
Path currentJar = null;
if (jarFiles.length > 2) {
for (int i = 1; i < (jarFiles.length - 1); i++) {
Path nestedJar = currentFs.getPath(jarFiles[i]);
Path extractedJar = Files.createTempFile("jar-" + i, ".jar");
Files.copy(nestedJar, extractedJar, StandardCopyOption.REPLACE_EXISTING);
currentFs.close();
if (currentJar != null) {
Files.delete(currentJar);
}
currentJar = extractedJar;
currentFs = FileSystems.newFileSystem(URI.create("jar:file:" + extractedJar),
Map.of("create", "true"));
}
}
return currentFs;
}
Returning a list of filesystems so you can close them all after use and not leak FD's. The last FileSystem will be able to get your desired directory/object/etc
Solution 2:[2]
The problem is solved at least in Java 14 (maybe earlier). OP's code works there with one change: you need to add an explicit cast to ClassLoader for the second argument of newFileSystem.
For a more complete example, this code prints the contents of README.md which is inside the internal.zip archive which itself is inside the archive.zip archive:
import java.io.IOException;
import java.nio.file.*;
public class Test {
public static void main(String[] args) throws IOException {
Path zipfile = Paths.get("archive.zip");
FileSystem manager = FileSystems.newFileSystem(zipfile, (ClassLoader) null);
Path internal = manager.getPath("internal.zip");
FileSystem internalManager = FileSystems.newFileSystem(internal, (ClassLoader) null);
Path internalFile = internalManager.getPath("README.md");
Files.lines(internalFile).forEach(System.out::println);
}
}
Note that file names inside archives are case-sensitive.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | vadipp |
