Android解压zip rar 7z文件

添加依赖

implementation 'org.apache.commons:commons-compress:1.23.0'
implementation 'com.github.junrar:junrar:7.5.4'//解压rar
implementation 'org.tukaani:xz:1.9'//解压.7z文件需要

下面 FileUtil.kt 代码中用到了 Context 的拓展方法 getAppDir

fun Context.getAppDir() = getExternalFilesDir("")!!.absolutePath

解压文件的代码 FileUtil.kt

import android.content.Context
import android.net.Uri
import android.provider.OpenableColumns
import android.util.Log
import com.github.junrar.Junrar
import org.apache.commons.compress.archivers.ArchiveEntry
import org.apache.commons.compress.archivers.ArchiveStreamFactory
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry
import org.apache.commons.compress.archivers.sevenz.SevenZFile
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
import org.apache.commons.compress.archivers.zip.ZipFile
import java.io.Closeable
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.util.Enumeration

private const val ZIP = ".zip"
private const val RAR = ".rar"
private const val SEVEN_Z = ".7z"

object FileUtil {
    private const val TAG = "FileUtil"

    val MIME_TYPES = arrayOf(
        "application/zip", //压缩比例小,耗时少
        "application/rar",
        "application/x-7z-compressed", //压缩比例大,耗时多
    )


    private fun getFileName(context: Context, uri: Uri): String? {
        var filename: String? = null
        val cursor = context.contentResolver.query(uri, null, null, null, null)
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                if (nameIndex > -1) {
                    filename = cursor.getString(nameIndex)
                    Log.i(TAG, "文件名称 $filename")
                }
            }
            cursor.close()
        }
        return filename
    }

    /**
     * 解压文件
     *
     * @return 返回解压后的文件所在的目录
     */
    fun extractFiles(context: Context, uri: Uri): String? {
        val filename = getFileName(context, uri)
        Log.i(TAG, "解压文件 $filename")
        if (filename != null) {
            context.contentResolver.openInputStream(uri)?.use { istream ->
                //由于Android系统对外部存储访问的限制,使用系统框架选取文件,
                //复制到APP专用的外部存储目录中(即 context.getExternalFilesDir("")!!.absolutePath),然后进行解压
                val copyPath = context.getAppDir() + "/" + filename
                FileOutputStream(copyPath).use { ostream ->
                    istream.copyTo(ostream)
                    Log.i(TAG, "文件复制完毕 $copyPath")
                    //解压文件
                    val outDir = when {
                        filename.endsWith(ZIP) -> uncompressFile(context, copyPath, ZipFile::class.java, ZipArchiveEntry::class.java)
                        filename.endsWith(SEVEN_Z) -> uncompressFile(context, copyPath, SevenZFile::class.java, SevenZArchiveEntry::class.java)
                        filename.endsWith(RAR) -> unrar(context, copyPath)
                        else -> null
                    }
                    if (outDir != null) {
                        Log.i(TAG, "解压完毕 $outDir")
                        val deleteSuccess = File(copyPath).delete()
                        Log.i(TAG, "删除临时文件 $copyPath $deleteSuccess")
                    }
                    return outDir
                }
            }
        }
        return null
    }

    private fun extractFiles(context: Context, filePath: String, archiverName: String): String? {
        if (!File(filePath).exists()) {
            return null
        }
        val appDir = context.getAppDir()
        var outDir = appDir
        val factory = ArchiveStreamFactory("UTF-8")
        FileInputStream(filePath).use { istream ->
            // 7z doesn't support streaming
            val archiveInputStream = factory.createArchiveInputStream(archiverName, istream)
            var archiveEntry: ArchiveEntry? = archiveInputStream.nextEntry
            val entryNameList = mutableListOf<String>()
            while (archiveEntry != null) {
                if (archiveEntry.isDirectory) {
                    outDir = appDir + "/" + archiveEntry.name
                    val dir = File(outDir)
                    if (!dir.exists()) dir.mkdirs()
                } else {
                    Log.i(TAG, "压缩包中包含的文件: ${archiveEntry.name}")
                    entryNameList.add(archiveEntry.name)
                }
                archiveEntry = archiveInputStream.nextEntry
            }
            Log.e(TAG, "outDir=$outDir")
            for (entryName in entryNameList) {
                FileOutputStream("$appDir/$entryName").use { ostream ->
                    istream.copyTo(ostream)
                }
            }
            archiveInputStream.close()
        }
        Log.i(TAG, "解压完毕")
        return outDir
    }


    private fun <TFile : Closeable, TArchiveEntry : ArchiveEntry> uncompressFile(
        context: Context, filePath: String,
        cls: Class<TFile>, clsArchiveEntry: Class<TArchiveEntry>
    ): String? {
        val file = File(filePath)
        if (!file.exists()) {
            return null
        }
        val startTime = System.currentTimeMillis()
        val constructor = cls.getDeclaredConstructor(File::class.java)
        val closeableFile = constructor.newInstance(file)
        val entriesObj = cls.getDeclaredMethod("getEntries").invoke(closeableFile)
        val entries = if (entriesObj is Iterable<*>) {
            (entriesObj as Iterable<TArchiveEntry>).toList()
        } else {
            (entriesObj as Enumeration<TArchiveEntry>).toList()
        }
        val appDir = context.getAppDir()
        var outDir = appDir
        val entryList = mutableListOf<TArchiveEntry>()
        for (archiveEntry in entries) {
            if (archiveEntry.isDirectory) {
                outDir = appDir + "/" + archiveEntry.name
                val dir = File(outDir)
                if (!dir.exists()) dir.mkdirs()
            } else {
                Log.i(TAG, "压缩包中的文件: ${archiveEntry.name}")
                entryList.add(archiveEntry)
            }
        }

        val getInputStreamMethod = cls.getDeclaredMethod("getInputStream", clsArchiveEntry)
        for (archiveEntry in entryList) {
            (getInputStreamMethod.invoke(closeableFile, archiveEntry) as InputStream).use { istream ->
                FileOutputStream(appDir + "/" + archiveEntry.name).use { ostream ->
                    istream.copyTo(ostream)
                }
            }
        }
        closeableFile.close()
        val time = System.currentTimeMillis() - startTime
        val suffix = filePath.substring(filePath.lastIndexOf('.'))
        Log.i(TAG, "解压 $suffix 耗时 $time ms")
        return outDir
    }

    /**
     * 解压7z
     */
    private fun un7z(context: Context, filePath: String): String? {
        if (!File(filePath).exists()) {
            return null
        }

        val _7zFile = SevenZFile(File(filePath))
        val files = _7zFile.entries.toList()
        val appDir = context.getAppDir()
        var outDir = appDir
        val entryList = mutableListOf<SevenZArchiveEntry>()
        for (archiveEntry in files) {
            if (archiveEntry.isDirectory) {
                outDir = appDir + "/" + archiveEntry.name
                val dir = File(outDir)
                if (!dir.exists()) dir.mkdirs()
            } else {
                Log.i(TAG, "7Z中包含的文件: ${archiveEntry.name}")
                entryList.add(archiveEntry)
            }
        }
        for (archiveEntry in entryList) {
            _7zFile.getInputStream(archiveEntry).use { istream ->
                FileOutputStream(appDir + "/" + archiveEntry.name).use { ostream ->
                    istream.copyTo(ostream)
                }
            }
        }
        _7zFile.close()
        Log.i(TAG, "7Z解压完毕")
        return outDir
    }


    
    /**
     * 解压rar
     */
    private fun unrar(context: Context, rarFilePath: String): String? {
        val rarFile = File(rarFilePath)
        if (!rarFile.exists()) {
            return null
        }
        val startTime = System.currentTimeMillis()
        val appDir = context.getAppDir()
        var outDir = appDir

        val files = Junrar.extract(rarFile, File(context.getAppDir()))
        for (file in files) {
            if (file.isDirectory) {
                outDir = file.absolutePath
                break
            }
        }
        /*val contentDescriptions: List<ContentDescription> = Junrar.getContentsDescription(rarFile)
        for (item in contentDescriptions) {
            Log.i(TAG, "RAR中文件 ${item.path}")
        }*/
        val time = System.currentTimeMillis() - startTime
        Log.i(TAG, "解压 rar 耗时 $time ms")
        return outDir
    }


    /**
     * 解压zip
     */
    fun unzip(context: Context, zipFilePath: String): String? {
        if (!File(zipFilePath).exists()) {
            return null
        }

        val zipFile = ZipFile(zipFilePath)
        val files = zipFile.entries.toList()
        val appDir = context.getAppDir()
        var outDir = appDir
        val entryList = mutableListOf<ZipArchiveEntry>()
        for (zipEntry in files) {
            if (zipEntry.isDirectory) {
                outDir = appDir + "/" + zipEntry.name
                val dir = File(outDir)
                if (!dir.exists()) dir.mkdirs()
            } else {
                Log.i(TAG, "ZIP中包含的文件: ${zipEntry.name}")
                entryList.add(zipEntry)
            }
        }
        for (zipEntry in entryList) {
            zipFile.getInputStream(zipEntry).use { istream ->
                FileOutputStream(appDir + "/" + zipEntry.name).use { ostream ->
                    istream.copyTo(ostream)
                }
            }
        }
        zipFile.close()
        Log.i(TAG, "ZIP解压完毕")
        return outDir
    }
}

选择文件

val launcher: ActivityResultLauncher<Array<String>> = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
            it?.let { uri ->
                executor.execute {
                    //解压文件
                    FileUtil.extractFiles(context, uri)?.let { outDir ->
                        //获得解压文件所在的目录
                    }
                }
            }
        }

//选择文件
launcher.launch(FileUtil.MIME_TYPES)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
应用简介: RAR for Android 是来自RARLAB的官方版本,是PC端 winrar 的姐妹,支持创建RARZIP压缩文件,能够轻松解压RAR, RAR5, ZIP, TAR, GZ, BZ2, XZ, 7z, ISO, ARJ等格式的文件,是手机端不可多得的神器! 主要功能: - 支持创建RARZIP压缩文件以及解压RAR, RAR5, ZIP, TAR, GZ, BZ2, XZ, 7z, ISO, ARJ等格式的文件 - 支持修复 ZIPRAR 压缩文件,支持进行基准测试(基准测试能够测试数据处理的速度,检查错误等) - 基准测试与WinRAR兼容,请使用相同的版本在不同的设备之间进行数据测试比较,不同版本数据会相差很大 - 支持恢复记录,恢复卷,固实压缩,多核压缩,设置加密,设置配置文件,设置默认配置,重新组织配置文件 - 支持压缩后删除源文件,设置压缩文件名称,可选:标准,最快,较快,较好,最好等压缩方式,自定义字典大小 - 可设置分卷压缩文件大小,以及恢复分卷数量,支持创建每个压缩卷后自动暂停,支持显示压缩时间,显示名称 - 支持设置压缩文件名称掩码,创建压缩文件时附加当前日期字符串到压缩文件名,常用于每日备份. - 内置帮助内容,可自行阅读。支持删除压缩文件中的文件,支持创建单独压缩,自定义解压目录等 - 支持长时间操作后发出哔声提醒,自定义启动文件夹,可按照习惯排序文件夹,设置压缩文件优先 更新日志: - 压缩,新建文件夹,重命名命令在动画文件列表中,现在可以快速定位了 - RAR可以通过“共享”命令,接受更多格式。例如,图片可以从Android库共享
Android 平台上解压 ZIP 文件,你可以使用以下代码示例: ```java import android.util.Log; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; public class ZipUtils { private static final int BUFFER_SIZE = 4096; public static void unzip(String zipFilePath, String destDirectory) { try { File destDir = new File(destDirectory); if (!destDir.exists()) { destDir.mkdir(); } ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFilePath)); ZipEntry entry = zipIn.getNextEntry(); while (entry != null) { String filePath = destDirectory + File.separator + entry.getName(); if (!entry.isDirectory()) { extractFile(zipIn, filePath); } else { File dir = new File(filePath); dir.mkdir(); } zipIn.closeEntry(); entry = zipIn.getNextEntry(); } zipIn.close(); } catch (Exception e) { Log.e("ZipUtils", "Error while unzipping file: " + e.getMessage()); } } private static void extractFile(ZipInputStream zipIn, String filePath) { try { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath)); byte[] bytesIn = new byte[BUFFER_SIZE]; int read; while ((read = zipIn.read(bytesIn)) != -1) { bos.write(bytesIn, 0, read); } bos.close(); } catch (Exception e) { Log.e("ZipUtils", "Error while extracting file: " + e.getMessage()); } } } ``` 使用上述代码,你只需调用 `unzip` 方法,传入 ZIP 文件的路径和解压目标目录的路径即可。注意确保你的应用已经获取了文件读写权限。 示例用法: ```java String zipFilePath = "/path/to/your/zip/file.zip"; String destDirectory = "/path/to/your/destination/directory"; ZipUtils.unzip(zipFilePath, destDirectory); ``` 将上述路径替换为你实际的文件路径和目标目录路径。 希望对你有所帮助!如有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值