I am trying to read a zipped file using Kotlin and ZipInputStream into a 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
}
The error I get is:
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>
I thought maybe zis.use
is closing the entry already after the contents of the entry are read, so I removed zis.closeEntry()
, but then it produced the same error when trying to get the next entry
I know zis.use
is safe and guarantees the input stream is closed, but I would expect it to close just the entry if anything rather than the entire stream.
Having printed the entire byte array, I know only the first file in the zip is being read during zis.use
Is there a good way to read all entries in a ZipInputStream in kotlin?
Is there a good way to read all entries in a ZipInputStream in kotlin?
Here's a function to extract the files from a Zip file, which you can use as a base and adjust to your own needs:
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()
}
The key point is to use generateSequence
to handle iterating over the entries until there are none left.
Example usage, extracing a zip that contains three text files in a directory:
fun main() {
val unzipped = unzip(File("zipped.zip"))
for ((filename, content) in unzipped) {
println("Contents of $filename: '${content.toString(Charset.defaultCharset()).trim()}'")
}
}
Output:
Contents of zipped/two.txt: 'contents of two'
Contents of zipped/three.txt: 'three!!!!'
Contents of zipped/one.txt: 'contents of one'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With