在 Kotlin 中读取 ZipInputStream
Read ZipInputStream in Kotlin
我正在尝试使用 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 中所有条目的好方法吗?
use
函数调用 close() method, which closes the entire stream, rather than closeEntry(),它仅关闭当前条目。我认为你应该用 zis.use { ... }
包装整个 while
循环,而不是为每个条目调用它。
在 Kotlin 中,use
将关闭实现 AutoCloseable
的资源。这意味着它的 close()
方法会自动为您调用。我认为您假设在 ZipInputStream
中已被覆盖以仅关闭条目,但事实并非如此。
Closes this input stream and releases any system resources associated with the stream. [Emphasis mine]
Is there a good way to read all entries in a ZipInputStream in kotlin?
这里有一个从 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
处理条目的迭代,直到剩下 none。
示例用法,解压一个目录中包含三个文本文件的 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'
我正在尝试使用 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
在 kotlin 中有读取 ZipInputStream 中所有条目的好方法吗?
use
函数调用 close() method, which closes the entire stream, rather than closeEntry(),它仅关闭当前条目。我认为你应该用 zis.use { ... }
包装整个 while
循环,而不是为每个条目调用它。
在 Kotlin 中,use
将关闭实现 AutoCloseable
的资源。这意味着它的 close()
方法会自动为您调用。我认为您假设在 ZipInputStream
中已被覆盖以仅关闭条目,但事实并非如此。
Closes this input stream and releases any system resources associated with the stream. [Emphasis mine]
Is there a good way to read all entries in a ZipInputStream in kotlin?
这里有一个从 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
处理条目的迭代,直到剩下 none。
示例用法,解压一个目录中包含三个文本文件的 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'