在 kotlin 脚本 [.kts] 中解压缩文件



我正在考虑用 kotlin 脚本重写一些现有的 bash 脚本。

其中一个脚本有一个部分,用于解压缩目录中的所有文件。在 bash:

unzip *.zip

有没有一种很好的方法可以在 kotlin 脚本中解压缩文件?

最简单的方法是只使用 exec unzip(假设 zip 文件的名称存储在zipFileName变量中):

ProcessBuilder()
    .command("unzip", zipFileName)
    .redirectError(ProcessBuilder.Redirect.INHERIT)
    .redirectOutput(ProcessBuilder.Redirect.INHERIT)
    .start()
    .waitFor()

不同的方法,更可移植(它将在任何操作系统上运行并且不需要unzip可执行文件存在),但功能不那么完整(它不会恢复Unix权限),是在代码中进行解压缩:

import java.io.File
import java.util.zip.ZipFile
ZipFile(zipFileName).use { zip ->
    zip.entries().asSequence().forEach { entry ->
        zip.getInputStream(entry).use { input ->
            File(entry.name).outputStream().use { output ->
                input.copyTo(output)
            }
        }
    }
}

如果您需要扫描所有文件*.zip那么您可以这样做:

File(".").list { _, name -> name.endsWith(".zip") }?.forEach { zipFileName ->
    // any of the above approaches        
}

或者像这样:

import java.nio.file.*
Files.newDirectoryStream(Paths.get("."), "*.zip").forEach { path ->
    val zipFileName = path.toString()
    // any of the above approaches        
}

此代码用于从资产解压缩

1.首先要取消zping,您需要InputStream
2.放入ZipInputStream
3.如果目录不存在,您必须通过.mkdirs()

private val BUFFER_SIZE = 8192//2048;
private val SDPath = Environment.getExternalStorageDirectory().absolutePath
private val unzipPath = "$SDPath/temp/zipunzipFile/unzip/"
var count: Int
    val buffer = ByteArray(BUFFER_SIZE)

    val context: Context = this
    val am = context.getAssets()
    val stream = context.getAssets().open("raw.zip")
 try {
 ZipInputStream(stream).use { zis ->
    var ze: ZipEntry
    while (zis.nextEntry.also { ze = it } != null) {
        var fileName = ze.name
        fileName = fileName.substring(fileName.indexOf("/") + 1)
        val file = File(unzipPath, fileName)
        val dir = if (ze.isDirectory) file else file.getParentFile()
        if (!dir.isDirectory() && !dir.mkdirs())
            throw FileNotFoundException("Invalid path: " + dir.getAbsolutePath())
        if (ze.isDirectory) continue
        val fout = FileOutputStream(file)
        try {
            while ( zis.read(buffer).also { count = it } != -1)
                fout.write(buffer, 0, count)
        } finally {
   val fout : FileOutputStream =openFileOutput(fileName, Context.MODE_PRIVATE)
            fout.close()
        }
    }

对于从外部存储解压缩:

private val sourceFile= "$SDPath/unzipFile/data/"
ZipInputStream zis = null;
    try {
        zis = new ZipInputStream(new BufferedInputStream(new 
 FileInputStream(sourceFile)));
        ZipEntry ze;
        int count;
        byte[] buffer = new byte[BUFFER_SIZE];
        while ((ze = zis.getNextEntry()) != null) {
            String fileName = ze.getName();
            fileName = fileName.substring(fileName.indexOf("/") + 1);
            File file = new File(destinationFolder, fileName);
            File dir = ze.isDirectory() ? file : file.getParentFile();
            if (!dir.isDirectory() && !dir.mkdirs())
                throw new FileNotFoundException("Invalid path: " + 
  dir.getAbsolutePath());
            if (ze.isDirectory()) continue;
            FileOutputStream fout = new FileOutputStream(file);
            try {
                while ((count = zis.read(buffer)) != -1)
                    fout.write(buffer, 0, count);
            } finally {
                fout.close();
            }
        }
    } catch (IOException ioe) {
        Log.d(TAG, ioe.getMessage());
        return false;
    } finally {
        if (zis != null)
            try {
                zis.close();
            } catch (IOException e) {
            }
    }
    return true;

如果 zip 的第一个条目是目录,则接受的答案将失败。这是一个稍微修改的解决方案来处理这个问题。

/**
 * Extract a zip file into any directory
 *
 * @param zipFile src zip file
 * @param extractTo directory to extract into.
 * There will be new folder with the zip's name inside [extractTo] directory.
 * @param extractHere no extra folder will be created and will be extracted
 * directly inside [extractTo] folder.
 *
 * @return the extracted directory i.e, [extractTo] folder if [extractHere] is `true`
 * and [extractTo]zipFile folder otherwise.
 */
private fun extractZipFile(
    zipFile: File,
    extractTo: File,
    extractHere: Boolean = false,
): File? {
    return try {
        val outputDir = if (extractHere) {
            extractTo
        } else {
            File(extractTo, zipFile.nameWithoutExtension)
        }
        ZipFile(zipFile).use { zip ->
            zip.entries().asSequence().forEach { entry ->
                zip.getInputStream(entry).use { input ->
                    if (entry.isDirectory) {
                        val d = File(outputDir, entry.name)
                        if (!d.exists()) d.mkdirs()
                    } else {
                        val f = File(outputDir, entry.name)
                        if (f.parentFile?.exists() != true)  f.parentFile?.mkdirs()
                        f.outputStream().use { output ->
                            input.copyTo(output)
                        }
                    }
                }
            }
        }
        extractTo
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

最新更新