3

Can a java.nio.file.FileSystem be created for a zip file that's inside a zip file?

If so, what does the URI look like?

If not, I'm presuming I'll have to fall back to using ZipInputStream.

I'm trying to recurse into the method below. Current implementation creates a URI "jar:jar:...". I know that's wrong (and a potentially traumatic reminder of a movie character). What should it be?

private static void traverseZip(Path zipFile ) {
    // Example: URI uri = URI.create("jar:file:/codeSamples/zipfs/zipfstest.zip");
    
    String sURI = "jar:" + zipFile.toUri().toString();
    URI uri = URI.create(sURI);

    Map<String, String> env = new HashMap<>();

    try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {

        Iterable<Path> rootDirs = fs.getRootDirectories();
        for (Path rootDir : rootDirs) {
            traverseDirectory(rootDir ); // Recurses back into this method for ZIP files
        }

    } catch (IOException e) {
        System.err.println(e);
    }
}
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151

1 Answers1

3

You can use FileSystem.getPath to return a Path suitable for use with another FileSystems.newFileSystem call which opens the nested ZIP/archive.

For example this code opens a war file and reads the contents of the inner jar file:

Path war = Path.of("webapps.war");
String pathInWar = "WEB-INF/lib/some.jar";

try (FileSystem fs = FileSystems.newFileSystem(war)) {
    
    Path jar = fs.getPath(pathInWar);

    try (FileSystem inner = FileSystems.newFileSystem(jar)) {
        for (Path root : inner.getRootDirectories()) {
            try (Stream<Path> stream = Files.find(root, Integer.MAX_VALUE, (p,a) -> true)) {
                stream.forEach(System.out::println);
            }
        }
    }
}

Note also that you code can pass in zipFile without changing to URI:

try (FileSystem fs = FileSystems.newFileSystem(zipFile, env)) {
DuncG
  • 12,137
  • 2
  • 21
  • 33
  • Using the Path constructor instead of converting to a URI solved the problem. I'm now recursing into zips inside zips. Thank you! – Andy Thomas Dec 17 '21 at 20:53
  • Important note: `FileSystems.newFileSystem(Path)` was only added in Java 13, so those using Java 11 or 8 can't use this method: https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/nio/file/FileSystems.html#newFileSystem(java.nio.file.Path) – byteit101 Mar 18 '22 at 18:11