我正在考虑用 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
}
}