kotlin對ZipInputStream與ZipOutputStream的一些擴充工具(壓縮,解壓)

GSOC發表於2018-04-20

使用方法:通過file或流直接建立ZipInputStream ZipOutputStream

val zipOut = File("C:\\Users\\admin\\Desktop\\output.zip").zipOutputStream()
val zipIn = File("C:\\Users\\admin\\Desktop\\output.zip").zipInputStream()
val zipOut = xxOutputStream.zipOutputStream()
val zipIn = xxInputStream.zipInputStream()
複製程式碼

對多檔案,資料夾進行壓縮處理(支援空資料夾)

File("C:\\Users\\admin\\Desktop\\output.zip")
            .zipOutputStream()
            .zipFrom(
                    "C:\\Users\\admin\\Desktop\\SophixPatchTool_windows",
                    "F:\\MUSIC\\Justin Bieber - Love Yourself.flac")
//上述程式碼將SophixPatchTool_windows資料夾與Justin Bieber - Love Yourself.flac壓縮到C:\\Users\\admin\\Desktop\\output.zip目錄下

複製程式碼

將zip檔案壓縮到指定目錄

將zip檔案壓縮到指定目錄C:\\Users\\admin\\Desktop\\66
File("C:\\Users\\admin\\Desktop\\output.zip").unZipTo("C:\\Users\\admin\\Desktop\\66")
或者
File("C:\\Users\\admin\\Desktop\\output.zip") unZipTo "C:\\Users\\admin\\Desktop\\66"
複製程式碼

程式碼主要是一些遞迴的演算法,以及大量使用了kotlin的擴充函式,並且使用了中綴表示式 並沒有比較難的地方,程式碼貼上


fun File.zipInputStream() = ZipInputStream(this.inputStream())

fun File.zipOutputStream() = ZipOutputStream(this.outputStream())

fun InputStream.zipInputStream() = ZipInputStream(this)

fun OutputStream.zipOutputStream() = ZipOutputStream(this)

infix fun File.unZipTo(path: String) {
    //使用GBK編碼,避免壓縮中文檔名亂碼
    checkUnzipFolder(path)
    ZipFile(this, Charset.forName("GBK")) unZipTo path
}

infix fun ZipFile.unZipTo(path: String) {
    checkUnzipFolder(path)
    for (entry in entries()) {
        //判斷是否為資料夾
        if (entry.isDirectory) {
            File("${path}/${entry.name}").mkdirs()
        } else {
            val input = getInputStream(entry)
            val outputFile = File("${path}/${entry.name}")
            if (!outputFile.exists()) outputFile.smartCreateNewFile()
            val output = outputFile.outputStream()
            input.writeTo(output, DEFAULT_BUFFER_SIZE)
        }
    }
}

/**
 * 檢查路徑正確性
 */
private fun checkUnzipFolder(path: String) {
    val file = File(path)
    if (file.isFile) throw RuntimeException("路徑不能是檔案")
    if (!file.exists()) {
        if (!file.mkdirs()) throw RuntimeException("建立資料夾失敗")
    }
}

fun ZipOutputStream.zipFrom(vararg srcs: String) {

    val files = srcs.map { File(it) }

    files.forEach {
        if (it.isFile) {
            zip(arrayOf(it), null)
        } else if (it.isDirectory) {
            zip(it.listFiles(), it.name)
        }
    }
    this.close()
}

private fun ZipOutputStream.zip(files: Array<File>, path: String?) {
    //字首,用於構造路徑
    val prefix = if (path == null) "" else "$path/"

    if (files.isEmpty()) createEmptyFolder(prefix)

    files.forEach {
        if (it.isFile) {
            val entry = ZipEntry("$prefix${it.name}")
            val ins = it.inputStream().buffered()
            putNextEntry(entry)
            ins.writeTo(this, DEFAULT_BUFFER_SIZE, closeOutput = false)
            closeEntry()
        } else {
            zip(it.listFiles(), "$prefix${it.name}")
        }
    }
}

/**
 * inputstream內容寫入outputstream
 */
fun InputStream.writeTo(outputStream: OutputStream, bufferSize: Int = 1024 * 2,
                        closeInput: Boolean = true, closeOutput: Boolean = true) {

    val buffer = ByteArray(bufferSize)
    val br = this.buffered()
    val bw = outputStream.buffered()
    var length = 0

    while ({ length = br.read(buffer);length != -1 }()) {
        bw.write(buffer, 0, length)
    }

    bw.flush()

    if (closeInput) {
        close()
    }

    if (closeOutput) {
        outputStream.close()
    }
}

/**
 * 生成一個壓縮檔案的資料夾
 */
private fun ZipOutputStream.createEmptyFolder(location: String) {
    putNextEntry(ZipEntry(location))
    closeEntry()
}

fun File.smartCreateNewFile(): Boolean {

    if (exists()) return true
    if (parentFile.exists()) return createNewFile()

    if (parentFile.mkdirs()) {
        if (this.createNewFile()) {
            return true
        }
    }
    return false
}

複製程式碼

相關文章