Skip to content

Instantly share code, notes, and snippets.

@DRSchlaubi
Last active April 16, 2022 17:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DRSchlaubi/88203fd8dd8d2d83c992cae9b9d1bad5 to your computer and use it in GitHub Desktop.
Save DRSchlaubi/88203fd8dd8d2d83c992cae9b9d1bad5 to your computer and use it in GitHub Desktop.
Kotlin zip utils
/*
* Copyright 2020 Michael Rittmeister
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.devcordde.devcordbot.util
import java.io.FileInputStream
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
fun unzipFile(path: Path, into: Path, strip: Int = 0, delete: Boolean = true) {
val stream = ZipInputStream(FileInputStream(path.toFile()))
val buffer = ByteArray(1024)
stream.use {
it.asIterable().forEach { entry ->
val destination = Path.of(entry.name)
val sanitizedDestination = if (destination.nameCount > strip) {
destination.subpath(strip, destination.nameCount)
} else destination
val finalDestination = into.resolve(sanitizedDestination)
if (finalDestination.parent?.let { parent -> !Files.exists(parent) } == true) {
Files.createDirectories(finalDestination.parent)
}
if (entry.isDirectory) {
if (sanitizedDestination.nameCount > strip) {
if (!Files.exists(finalDestination)) {
Files.createDirectories(finalDestination)
}
}
} else {
Files.createFile(finalDestination)
FileChannel.open(finalDestination, StandardOpenOption.WRITE).use { writer ->
while (it.read(buffer) > 0) {
writer.write(ByteBuffer.wrap(buffer))
}
}
}
}
}
if (delete) {
Files.deleteIfExists(path)
}
}
private fun ZipInputStream.asIterable(): Iterable<ZipEntry> = object : Iterable<ZipEntry> {
override fun iterator(): Iterator<ZipEntry> = ZipIterator(this@asIterable)
}
private class ZipIterator(private val stream: ZipInputStream) : Iterator<ZipEntry> {
private var next: ZipEntry? = null
override fun hasNext(): Boolean {
next = stream.nextEntry
return next != null
}
override fun next(): ZipEntry = next ?: throw NoSuchElementException()
}
@hrules6872
Copy link

ZipIterator class doesn't work correctly because the scope function also in next method move the pointer inside ZipInputStream.

You should use this version:

private class ZipIterator(private val stream: ZipInputStream) : Iterator<ZipEntry> {
  private var next: ZipEntry? = null
  override fun hasNext(): Boolean {
    next = stream.nextEntry
    return next != null
  }

  override fun next(): ZipEntry = next ?: throw NoSuchElementException()
}

@DRSchlaubi
Copy link
Author

Thx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment