You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取AndroidP7zip库输出流以实现解压进度监听?

捕获AndroidP7zip的解压进度(Kotlin实现)

你提到的P7ZipApi.executeCommand应该是封装了基础的进程调用,但没暴露标准输出的捕获能力。要获取-bsp2输出的进度,得手动通过ProcessBuilder创建进程,然后读取其标准输出流。

核心实现思路

  • 用ProcessBuilder构建7z命令,替代封装好的executeCommand
  • 开启独立线程(或协程)读取进程的标准输出,避免阻塞主线程
  • 解析输出中的百分比数值,用于更新UI或记录进度

完整Kotlin代码示例

import android.os.Looper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.InputStreamReader

fun extractWithProgress(
    sourcePath: String,
    outputDir: String,
    password: String,
    onProgressUpdate: (Int) -> Unit,
    onExtractionComplete: (Boolean) -> Unit
) {
    // 构建7z命令,-bsp2指定输出进度到stdout
    val command = listOf(
        "7z",
        "x",
        sourcePath,
        "-o${outputDir}",
        "-p${password}",
        "-bsp2"
    )

    GlobalScope.launch(Dispatchers.IO) {
        var process: Process? = null
        try {
            process = ProcessBuilder(command).start()

            // 读取标准输出流
            BufferedReader(InputStreamReader(process.inputStream)).use { reader ->
                var line: String?
                while (reader.readLine().also { line = it } != null) {
                    line?.trim()?.let { progressLine ->
                        // 提取百分比数字(格式如"1%"、"100%")
                        val progress = progressLine.removeSuffix("%").toIntOrNull()
                        progress?.let {
                            // 切换到主线程更新UI
                            withContext(Dispatchers.Main) {
                                onProgressUpdate(it)
                            }
                        }
                    }
                }
            }

            // 等待进程结束,获取退出码
            val exitCode = process.waitFor()
            withContext(Dispatchers.Main) {
                onExtractionComplete(exitCode == 0)
            }
        } catch (e: Exception) {
            e.printStackTrace()
            withContext(Dispatchers.Main) {
                onExtractionComplete(false)
            }
        } finally {
            process?.destroy()
        }
    }
}

// 调用示例
fun startExtraction(externalFilesDir: String, password: String) {
    val source = "$externalFilesDir/meta.7z"
    val output = "$externalFilesDir/meta"

    extractWithProgress(source, output, password,
        onProgressUpdate = { progress ->
            // 这里更新UI,比如进度条
            // progressBar.progress = progress
        },
        onExtractionComplete = { success ->
            // 处理完成逻辑,比如提示用户
            // Toast.makeText(context, if (success) "解压完成" else "解压失败", Toast.LENGTH_SHORT).show()
        }
    )
}

关键注意点

  • 线程/协程选择:用Dispatchers.IO处理IO操作(读取流),更新UI必须切换到Dispatchers.Main,避免ANR
  • 流的关闭:用use关键字自动关闭BufferedReader,防止资源泄漏
  • 异常处理:捕获进程启动、流读取、命令执行中的异常,确保崩溃时能正确回调失败状态
  • 权限检查:确保已申请READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE(Android 13+可能需要更细粒度的权限)

替代方案(如果不想放弃P7ZipApi)

如果P7ZipApi是开源库,你可以修改其executeCommand方法,添加回调参数来传递stdout内容;如果是闭源的,就只能用上面的手动创建进程的方式。

内容的提问来源于stack exchange,提问作者metalex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:00:02