🐙

Kotlinでファイルを圧縮/展開する

2022/05/15に公開

KotlinでファイルをZip圧縮/展開するコードを実装したので。
ちなみにディスク容量のセーフティとかはかけていません。

ファイルを圧縮する

ファイルをZIPに圧縮するには ZipOutputStreamを使用します。

    // 指定したファイル/ディレクトリをZip圧縮する
    // ファイルはZipのルートに、ディレクトリは構造を維持して格納される
    fun archive(sources: List<File>, target: File): Unit {
        ZipOutputStream(target.outputStream()).use { zos ->
            sources.forEach { source->
                if(source.isDirectory.not()){
                    // ファイルならばそのままルートにデータを流し込む
                    zos.putNextEntry(ZipEntry(source.name))
                    source.inputStream().copyTo(zos, 256)
                }else{
                    // ディレクトリなら走査する
                    source.walk()
                        .filterNot { it.isHidden } // 隠しファイルは除外
                        .forEach {file->
                            if (file.isDirectory) {
                                // ディレクトリだった場合、Zipの中にディレクトリを切る
                                zos.putNextEntry(ZipEntry("${file.relativeTo(source)}/"))
                                zos.closeEntry()
                            } else {
                                // ファイルだった場合、データを流し込む
                                zos.putNextEntry(ZipEntry(file.relativeTo(source).toString()))
                                file.inputStream().copyTo(zos, 256)
                            }
                        }
                }
            }
        }
    }

ファイルを展開する

Zipファイルを展開するにはZipInputStreamを使用します。

    // ファイル展開する際に次のEntryを見ながらループを回すのに代入ループ(伝われ)が出来ないので拡張
    fun ZipInputStream.forEach(R: (ZipEntry)->Unit){
        var entry = nextEntry
        while (entry != null){
            R(entry)
            entry = nextEntry
        }
    }

    // 指定したZipファイルを任意の場所に展開する
    fun extract(source: Path, target: Path){
        ZipInputStream(Files.newInputStream(source)).use { zis->
            zis.forEach {entry->
                val dst = File(target.toFile(), entry.name)
                if(entry.isDirectory){
                    // エントリーがディレクトリならディレクトリ作成する
                    dst.mkdirs()
                }else{
                    // エントリーがファイルなら念の為にフォルダを切った後にデータを吸い出す
                    dst.parentFile?.mkdirs()
                    zis.copyTo(BufferedOutputStream(FileOutputStream(dst)))
                }
            }
        }
    }

Discussion