Работа с ZIP/архивами в Kotlin: полное руководство
В современной разработке на Kotlin (особенно для JVM и Android) часто возникает необходимость работать с ZIP-архивами: упаковывать логи, распаковывать ресурсы, создавать резервные копии или передавать данные в сжатом виде. В этой статье мы подробно разберем, как работать с ZIP-архивами в Kotlin, используя встроенные возможности Java (пакет java.util.zip), а также рассмотрим удобные расширения и альтернативы.
Зачем нужна работа с архивами в Kotlin?
- Экономия места — сжатие данных при хранении на диске.
- Удобство передачи — один архив вместо множества файлов.
- Безопасность — возможность шифрования (с дополнительными библиотеками).
- Работа с ресурсами — распаковка конфигураций или обновлений.
Основные классы Java для работы с ZIP
Kotlin полностью совместим с Java, поэтому для работы с архивами мы используем следующие классы из java.util.zip:
ZipOutputStream— для создания архива.ZipInputStream— для чтения архива.ZipEntry— представляет отдельный файл/папку внутри архива.ZipFile— удобный класс для чтения существующего архива.
Пример 1: Создание ZIP-архива в Kotlin
Создадим архив, который содержит несколько файлов и папок. Используем ZipOutputStream и BufferedOutputStream для повышения производительности.
import java.io.*
import java.util.zip.*
fun createZipArchive(
filesToZip: List<File>,
outputZipPath: String
) {
ZipOutputStream(BufferedOutputStream(FileOutputStream(outputZipPath))).use { zos ->
for (file in filesToZip) {
if (file.isDirectory) {
// Добавляем пустую папку
zos.putNextEntry(ZipEntry("${file.name}/"))
zos.closeEntry()
continue
}
// Добавляем файл
val entry = ZipEntry(file.name)
zos.putNextEntry(entry)
FileInputStream(file).use { fis ->
fis.copyTo(zos)
}
zos.closeEntry()
}
}
println("Архив создан: $outputZipPath")
}
fun main() {
val files = listOf(
File("document.txt"),
File("image.png"),
File("configs") // папка
)
createZipArchive(files, "output.zip")
}
Пример 2: Чтение содержимого ZIP-архива
Для просмотра списка файлов внутри архива удобно использовать ZipFile.
import java.util.zip.ZipFile
fun listZipContents(zipPath: String) {
ZipFile(zipPath).use { zip ->
println("Содержимое архива $zipPath:")
zip.entries().asSequence().forEach { entry ->
val size = if (entry.isDirectory) "папка" else "${entry.size} байт"
println("- ${entry.name} ($size)")
}
}
}
fun main() {
listZipContents("output.zip")
}
Пример 3: Распаковка ZIP-архива
Извлечем все файлы из архива в указанную папку. Обратите внимание на обработку вложенных папок.
import java.io.*
import java.util.zip.ZipInputStream
fun extractZip(
zipPath: String,
outputDir: String = "extracted"
) {
val destDir = File(outputDir)
destDir.mkdirs()
ZipInputStream(BufferedInputStream(FileInputStream(zipPath))).use { zis ->
var entry = zis.nextEntry
while (entry != null) {
val file = File(destDir, entry.name)
if (entry.isDirectory) {
file.mkdirs()
} else {
// Создаем родительские папки
file.parentFile?.mkdirs()
BufferedOutputStream(FileOutputStream(file)).use { bos ->
zis.copyTo(bos)
}
}
zis.closeEntry()
entry = zis.nextEntry
}
}
println("Архив распакован в $outputDir")
}
fun main() {
extractZip("output.zip", "my_output")
}
Расширения Kotlin для удобной работы с ZIP
Kotlin позволяет писать элегантные функции-расширения. Вот несколько полезных:
// Расширение для File
fun File.zipTo(destination: String) {
val files = if (this.isDirectory) this.walkTopDown().toList() else listOf(this)
ZipOutputStream(BufferedOutputStream(FileOutputStream(destination))).use { zos ->
for (file in files) {
val entryName = if (this.isDirectory) {
file.relativeTo(this