Kotlin在读取所有条目之前关闭ZipInputStream

时间:2018-09-12 14:24:14

标签: java kotlin zipinputstream

我正在尝试使用Kotlin和ZipInputStream将压缩文件读取到ByteArrayOutputStream()

val f = File("/path/to/zip/myFile.zip")
val zis = ZipInputStream(FileInputStream(f))

//loop through all entries in the zipped file
var entry = zis.nextEntry
while(entry != null) {
    val baos = ByteArrayOutputStream()

    //read the entry into a ByteArrayOutputStream
    zis.use{ it.copyTo(baos) }

    val bytes = baos.toByteArray()

    System.out.println(bytes[0])

    zis.closeEntry()  //error thrown here on first iteration
    entry = zis.nextEntry
}

我得到的错误是:

java.io.IOException: Stream closed
    at java.util.zip.ZipInputStream.ensureOpen(ZipInputStream.java:67)
    at java.util.zip.ZipInputStream.closeEntry(ZipInputStream.java:139)
    <the code above>

我以为zis.use可能已经在读取条目的内容之后关闭了该条目,所以我删除了zis.closeEntry(),但是在尝试获取下一个条目时却产生了相同的错误

我知道zis.use是安全的,并且可以确保输入流已关闭,但是我希望它只关闭条目(如果有的话),而不是整个流。

已经打印了整个字节数组,我知道在zis.use期间仅读取zip中的第一个文件

有没有一种好的方法来读取Kotlin中ZipInputStream中的所有条目?

3 个答案:

答案 0 :(得分:1)

use函数调用close()方法,该方法将关闭整个流,而不是closeEntry()方法,该方法仅关闭当前条目。我认为您应该用while包装整个zis.use { ... }循环,而不是为每个条目调用它。

答案 1 :(得分:1)

<块引用>

在 kotlin 中是否有读取 ZipInputStream 中所有条目的好方法?

这是从 Zip 文件中提取文件的函数,您可以将其用作基础并根据自己的需要进行调整:

data class UnzippedFile(val filename: String, val content: ByteArray)

fun unzip(file: File): List<UnzippedFile> = ZipInputStream(FileInputStream(file))
    .use { zipInputStream ->
        generateSequence { zipInputStream.nextEntry }
            .filterNot { it.isDirectory }
            .map {
                UnzippedFile(
                    filename = it.name,
                    content = zipInputStream.readAllBytes()
                )
            }.toList()
    }

关键点是使用 generateSequence 来处理对条目的迭代,直到没有条目为止。

示例用法,在一个目录中提取包含三个文本文件的 zip:

fun main() {
    val unzipped = unzip(File("zipped.zip"))
    for ((filename, content) in unzipped) {
        println("Contents of $filename: '${content.toString(Charset.defaultCharset()).trim()}'")
    }
}

输出:

Contents of zipped/two.txt: 'contents of two'
Contents of zipped/three.txt: 'three!!!!'
Contents of zipped/one.txt: 'contents of one'

答案 2 :(得分:0)

在Kotlin中,use将关闭实现AutoCloseable的资源。这意味着将自动为您调用其close()方法。我认为您假设在ZipInputStream中,该字段已被覆盖以仅关闭条目,但事实并非如此。

根据the documentation

  

关闭此输入流,并释放与该流关联的所有系统资源。 [强调我的]