Skip to main content
FileKit doesn’t create or extract archives itself. kmp-zip is a Kotlin Multiplatform zip library that works well with FileKit, because both use kotlinx-io streams. This recipe works with any PlatformFile, including files and folders returned by FileKit dialogs, such as Android content:// documents.

Dependencies

Add kmp-zip and its kotlinx-io adapters alongside FileKit Core:

Creating an archive

Supported on Android, iOS, macOS, JVM and Kotlin/Native Linux targets
The zip function below writes files and folders into an archive. Each folder keeps its name as the top-level entry, so extracting the archive recreates the folder:
Files are streamed into the archive, so large files are never fully loaded into memory. Sources must have distinct names, otherwise their entries would overwrite each other on extraction.
A few things to keep in mind:
  • Save the archive outside the files and folders you are zipping. Otherwise, zip can read the archive while writing it, or overwrite a source file before reading it.
  • Symbolic links are followed. A link to a parent folder makes zip loop through the same folders until it fails.
  • kmp-zip doesn’t support ZIP64. Each file and the archive must stay under 4 GB, with at most 65,535 entries.

Extracting an archive

Supported on Android, iOS, macOS, JVM and Kotlin/Native Linux targets
The unzip function extracts every entry into a destination folder:
Always validate entry names before extracting an archive you didn’t create. A malicious archive can contain names such as ../../file.txt to write files outside the destination folder (Zip Slip). This is what safePathSegments() prevents. Extract these archives into a new, empty folder: if the destination already contains a symbolic link, an entry could still be written through it.Untrusted archives can also be decompression bombs: a few kilobytes that extract to gigabytes. kmp-zip doesn’t limit the extracted size, so count the bytes you write and stop above a maximum. See the kmp-zip threat model for an example.

Example: Zipping files picked by the user

Combined with FileKit Dialogs, you can let the user pick files and choose where to save the archive:
To zip a whole folder, use FileKit.openDirectoryPicker() and pass the folder to zip.

Web

Supported on JS and WASM targets
source() and sink() are not available on web. You can still build the archive in memory and download it with FileKit.download:
The whole archive is kept in memory, so this approach is best suited for small files. See the kmp-zip documentation for more details about web support.

Going further

kmp-zip also supports password-protected archives (AES and legacy ZipCrypto), GZIP, and reading a single entry without extracting the whole archive. Check out the kmp-zip documentation for more details.