Skip to content

Getting Started

This guide covers adding KioArch to a Kotlin Multiplatform or single-platform Gradle build and performing common archive operations.


Gradle Setup

KioArch is published to Maven Central under the group ID com.sorrowblue.kioarch.

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("com.sorrowblue.kioarch:kioarch:0.3.3")
            implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.9.0")
        }
    }
}
[versions]
kioarch = "0.3.3"
kotlinx-io = "0.9.0"

[libraries]
kioarch = { module = "com.sorrowblue.kioarch:kioarch", version.ref = "kioarch" }
kotlinx-io-core = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
dependencies {
    implementation("com.sorrowblue.kioarch:kioarch:0.3.3")
    implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.9.0")
}

Basic Usage

1. Opening an Archive and Listing Entries

KioArch.createReader inspects the leading bytes of the input source, initializes the matching native decoder, and returns an ArchiveReader. Always wrap the reader in a .use { ... } block so native handles and the underlying SeekableSource are closed deterministically.

import com.sorrowblue.kioarch.KioArch
import kotlinx.io.files.Path

val archivePath = Path("path/to/archive.7z")

KioArch.createReader(archivePath).use { reader ->
    for (entry in reader.getEntries()) {
        val type = if (entry.isDirectory) "DIR " else "FILE"
        println("[$type] ${entry.name} (${entry.compressedSize} -> ${entry.size} bytes)")
    }
}

Path Normalization

Archive entry names (ArchiveEntry.name) are automatically normalized to use forward slashes (/) regardless of whether the archive was created on Windows or Unix.


2. Streaming an Entry into a Sink

To extract large files without allocating the entire uncompressed payload in heap memory, stream the entry into any kotlinx.io.Sink using ArchiveReader.extractEntry or the ArchiveEntry.extract extension:

import com.sorrowblue.kioarch.KioArch
import com.sorrowblue.kioarch.extract
import kotlinx.io.buffered
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem

KioArch.createReader(Path("archive.zip")).use { reader ->
    val target = reader.getEntries().first { !it.isDirectory && it.name == "docs/manual.pdf" }

    SystemFileSystem.sink(Path("output/manual.pdf")).buffered().use { sink ->
        with(reader) {
            target.extract(sink)
        }
        sink.flush()
    }
}

3. Extracting Small Entries to a ByteArray

For small configuration files, manifests, or thumbnails that fit comfortably in memory, use extractToByteArray:

import com.sorrowblue.kioarch.KioArch
import com.sorrowblue.kioarch.extractToByteArray
import kotlinx.io.files.Path

val jsonText: String = KioArch.createReader(Path("bundle.tar.gz")).use { reader ->
    val entry = reader.getEntries().first { it.name == "manifest.json" }
    with(reader) {
        entry.extractToByteArray().decodeToString()
    }
}

Error Handling

All native and I/O failures during header parsing or extraction are translated into subclasses of the sealed ArchiveException hierarchy:

Exception Class Cause
ArchiveUnsupportedException Unrecognized magic signature or unsupported compression method (such as encrypted headers).
ArchiveCorruptedException Truncated archive, invalid header structure, or CRC32 / bitstream verification failure.
ArchiveIOException Underlying SeekableSource read/seek failure or Sink write error.
ArchiveInvalidException Invalid entry index or illegal operation on a closed ArchiveReader.
ArchiveOutOfMemoryException Native decoder dictionary or heap allocation failure.
import com.sorrowblue.kioarch.ArchiveCorruptedException
import com.sorrowblue.kioarch.ArchiveException
import com.sorrowblue.kioarch.ArchiveUnsupportedException
import com.sorrowblue.kioarch.KioArch

try {
    KioArch.createReader(rawBytes).use { reader ->
        // Inspect or extract entries
    }
} catch (e: ArchiveUnsupportedException) {
    println("Unsupported archive format: ${e.message}")
} catch (e: ArchiveCorruptedException) {
    println("Archive is damaged or incomplete: ${e.message}")
} catch (e: ArchiveException) {
    println("Extraction failed: ${e.message}")
}