Java:使用路径的ZipFile

3
我有一个指向虚拟文件系统(jimfs)上zip文件的路径,我需要使用ZipFile打开这个zip文件。但是ZipFile中没有以Path作为参数的构造函数,只有File。然而,我无法从我的Path创建一个File(path.toFile()),因为我会收到UnsupportedOperationException。那么我应该如何使用ZipFile打开我的zip文件呢?或者也许还有其他处理zip文件的方式,不一定在默认文件系统上进行?

使用 ZipFile(String) 替代? - Yassin Hajaj
1
@Yassin Hajaj 我得到了 FileNotFoundException,因为它在默认文件系统上找到了该文件,但在虚拟文件系统上没有找到。 - Pavel_K
2个回答

3

ZipFile 类仅支持文件系统中的文件。

另一种选择是改用 ZipInputStream。可以使用以下方法从您的 Path 创建一个 InputStream

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

使用 InputStream 创建一个 ZipInputStream。这样应该能够正常工作:

ZipInputStream zin = new ZipInputStream(in)

所以建议使用它的方式是:
try (ZipInputStream zin = new ZipInputStream(Files.newInputStream(path))) {
    // do something with the ZipInputStream
}

请注意,使用ZipInputStream解压某些ZIP文件会因为它们的ZIP结构而失败。这是ZIP格式的技术限制,无法解决。在这种情况下,您必须在文件系统或内存中创建一个临时文件,并使用不同的ZIP类,如ZipFile

0

我刚刚解决了完全相同的问题(我需要解压缩存储在JimFS文件系统中的zip文件)。

罗伯特的回应存在问题。ZipFileZipInputStream相似,但并不相同。ZipInputStream的一个重要缺点是,如果遇到错误或损坏的zip文件,它不会失败,而是在第一次nextEntry调用时返回null。例如,以下测试将通过而没有错误。

    @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
            }
        }
    }

所以,如果存在用户输入或不稳定的网络获取的zip文件,在使用ZipInputStream检查zip文件时没有任何机会。唯一的选择是使用Java的FileSystems。以下测试将失败,并显示错误 zip END header not found 。当然,使用正确的zip文件,newFileSystem可以正常工作。
    @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())
        }
    }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接