Java: ZipFile using Path

4k Views Asked by At

I have a Path to zip file on virtual filesystem (jimfs) and I need to open this zip file using ZipFile.

But there is no constructor in ZipFile to get Path as argument, only File.

However, I can't create from my Path a File (path.toFile()) because I get UnsupportedOperationException. How can I open my zip file with ZipFile? Or maybe there are other ways of working with zip files which are not on default filesystem?

2

There are 2 best solutions below

0
On BEST ANSWER

The ZipFile class is limited to files in the file-system.

An alternative would be to use ZipInputStream instead. Create an InputStream from your Path using

Path path = ...
InputStream in = Files.newInputStream(path, openOptions)

and the use the InputStream to create an ZipInputStream. This way should work as expected:

ZipInputStream zin = new ZipInputStream(in)

So the recommended way to use it is:

try (ZipInputStream zin = new ZipInputStream(Files.newInputStream(path))) {
    // do something with the ZipInputStream
}

Note that decompressing certain ZIP files using ZipInputStream will fail because of their ZIP structure. This is a technical limitation of the ZIP format and can't be solved. In such cases you have to create a temporary file in file-system or memory and use a different ZIP class like ZipFile.

0
On

I just solved exactly the same problem (I need to unpack zip file stored on JimFS filesystem)

There is a problem with Robert's response. ZipFile and ZipInputStream similar, but not equal. One of big disadvantage of ZipInputStream - it's doesn't fail in case of wrong or damaged zip file. It just return null on first nextEntry call. For example following test will pass without errors

    @Test
    fun testZip() {
        val randomBytes = Random.nextBytes(1000)

        ZipInputStream(ByteArrayInputStream(randomBytes)).use { zis ->
            var zipEntry = zis.nextEntry
            while (zipEntry != null) {
                println(zipEntry.name)
                zipEntry = zis.nextEntry
            }
        }
    }

So, if in case of zip files obtained from user input or by unstable network, there isn't any chance to check zip using ZipInputStream. The only option here - to use Java's FileSystems. The following test will fail with error zip END header not found. With correct zip file newFileSystem works fine, of course.

    @Test
    fun testZipFS() {
        val randomBytes = Random.nextBytes(1000)

        val tmpFile = Files.createTempFile(Path.of("/tmp"), "tmp", ".zip")
        Files.write(tmpFile, randomBytes)

        val zipFs = FileSystems.newFileSystem(srcZip, null)

        val zipRoot = zipFs.rootDirectories.single()
        Files.walk(zipRoot).forEach { p ->
            println(p.absolutePathString())
        }
    }