On Android, I'm attempting to read a JSON file that is contained in a zip file which lives in my assets folder. The issue I'm running into is that it will throw an exception of java.io.IOException: Stream closed when I attempt to grab the non-existant nextEntry of the zipInputStream. Here is the block of code in question:
val awesomeList: ArrayList<AwesomeItem> = arrayListOf()
BufferedInputStream(manager.open("appData.zip")).use { bufferedInputStream ->
ZipInputStream(bufferedInputStream).use { zipInputStream ->
var zipEntry = zipInputStream.nextEntry
while (zipEntry != null) {
if (zipEntry.name == "awesomeList.json") {
JsonReader.of(Okio.buffer(Okio.source(zipInputStream))).use { reader ->
awesomeItems.addAll(readAwesomeArray(reader))
}
}
zipEntry = zipInputStream.nextEntry
}
}
}
private fun readAwesomeArray(reader: JsonReader): List<AwesomeItems> {
...
}
After stepping through the code using the debugger, the error gets thrown on the line zipEntry = zipInputStream.nextEntry after it has iterated through each file in the zip file (there are 4). I'm using Moshi's JsonReader to read the json file, and I know that works by inspecting the awesomeItems object when debugging paused using a breakpoint.
I'm familiar enough with Kotlin's use function to know that it will automatically close a stream when it is finished, but I am not sure which stream is getting closed, when it's getting closed, and why.
I'm interested in knowing the correct way to read a zip file's entries (from Android's assets folder) using Kotlin without throwing any exceptions. Most if not all of the examples on the web are in Java.
Note that
usewill have closed theAutoCloseableby the time the function returns.Also, when you open a
JsonReaderyou are using theZipInputStreamas its source. That means when the JSON reader is closed so too is the ZIP stream. This leads to your error since you try to process more data from the ZIP stream after closing the JSON reader.I can't guarantee this, but I believe in this case you don't have to worry about closing the
JsonReaderobjects, or theZipInputStreamobject for that matter. The object holding the "actual" resources that must be released in a timely manner is the (I assume)InputStreamreturned bymanager.open(...). You wrap that stream in aBufferedInputStreamwhich you close viause, releasing any resources held by the stream. This means you should be able to remove the use ofusewith theJsonReaderobjects and your code will work (without having to worry about a resource leak).