Search code examples
kotlinzipunzip

Extracting Zip contents into a flat directory using Kotlin


I'm working on some code to parse and extract the contents of a zip file. I finally figured out how to deal with nested zip archives (see: Extracting a Zip archive containing nested zip files using Kotlin for more details). However, now I am running into a new issue. I want all the files to be extracted into a single directory regardless of where they were nested. The code I have currently is creating directories for nested files and placing the extracted files there. What can I do to get everything into a single directory without having to shift files around after the function has run?

My code currently looks like:

internal fun File.unzipServiceFile(toPath: String): List<File>
{
    val retFiles = mutableListOf<File>()
    val stream =ZipInputStream(this.inputStream())
    stream.unzipServiceFile( toPath, retFiles)

    return retFiles
}

private fun ZipInputStream.unzipServiceFile( toPath: String, files:MutableList<File>) {

    var entry = nextEntry
    println("Parsing entry $entry")
    while( entry != null){
        println("entry: " + entry.name)
        //if there are nested zip files, we need to extract them
        if (entry.name.endsWith(".zip")) {
            //we need to go deeper
            ZipInputStream(this).unzipServiceFile(  toPath, files)
        }
        else if (entry.name.endsWith(".json") && !entry.isDirectory && !entry.name.startsWith(".") && !entry.name.startsWith(
                "_"
            )
        ) {
            val file = File("$toPath/${entry.name}")
            FileUtils.writeByteArrayToFile(file, readBytes())
            files.add(file)
            println("Added file ${file.path}")
        }

        entry = nextEntry
    }
    println()
}

Additional info:

The folder before being zipped: The folder before being zipped

The output of the code: The output from my function


Solution

  • entry.name is not just the file name, it may also contain a directory component. If you strip that when creating the output file then everything will be extracted in the same directory.

    One way to do it:

    val file = File("$toPath/${File(entry.name).name}")