Read YAML content of Zip file with a ZipInputStream

A problem that i recently had was, that i needed to read the contents of some zipped files, which i didn’t wanted to unzip into temp, because i really only needed the content as a String. I had some Zip files, which contain a Metadata.yaml file with some informations like id or title in it. I wanted to read the content of the Metadata.yaml file and put the values into a data class, which is then stored inside a HashMap.

Some of my files dont contain the Metadata.yaml file, so to compensate that, we use the documentTitle as the id of the HashMap and also as the id and title of the data class.

After a pretty long research about unzipping files in Kotlin I stumbled upon the ZipInputStream, which is essentially just a stream of data, which can be processed like any other Datatype.

getMetadata function

This function creates a ZipInputStream with the filePath. The file needs to exist for this operation to work. The documentTitle is just the name of the zipFile, but without the .zip extension.

This function triggers the mapObjects function and provides it with two Strings, one of which is generated by the getStringFromZip method. The second String is just the documentTitle, which we defined before. We will look at the getStringFromZip function down here.

getStringFromZip function

This function gets the ZipInputStream and the documentTitle from the getMetadata function and creates a new String called metadataString. It uses the ZipInputStream and creates a zipStream from it. Each zipStream is an entry in the ZipFile. It generates a sequence, which ensures, that all the entries get visited. Because I only want the Metadata.yaml file, I added a filter to the sequence, which matches the name of the entry to the Metadata.yaml.

For each entry, in which the filter criteria is true, (only one in my case) it overrides the metadataString and sets it to the content of the the Manifest file. In the end im just returning the metadataString.

mapObjects function

Since we now got the content of the file as a String from the previous method, we just have to read out the YAML values of the String.

fun mapObjects(str: String, documentTitle: String): Meta {
mapper.findAndRegisterModules()
return if (str != "") {
val meta: Meta = mapper.readValue<Meta>(str, Meta::class.java)
meta
} else {
Meta(documentTitle, documentTitle)
}
}
data class Meta(val id: String, val title: String)

First we have to create an ObjectMapper with a YAMLFactory. I defined it in a location out of the function because i want to use the same mapper multiple times and don’t want to create it every time.

As I mentioned before, not every File has a Manifest.yaml file and also not a String with content. If the String is empty, i just return the documentTitle as both the id and the title. If the String is not empty, it lets the mapper read the YAML values and puts it into the constructor of the data class.

Gradle Dependencies for the Mapper:

Add the values to a HashMap

Just create a new hashMap and put the two function calls in it. The id of the hashMap will be the id of the Manifest and the value of the hashMap will be the data class with the values in it.

metadata.put(getMetadata(zipFile).id, getMetadata(zipFile))

I hope you this article was useful and you are now able to read out contents of Zip files.

Developer Experience Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store