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

Android 10 Q下打包content URI格式音频为zip时提示文件不存在如何解决

问题原因

你直接将Content格式的URI传入File构造方法的逻辑本身是错误的。Content URI不属于本地文件绝对路径,系统不会通过文件系统直接访问该类资源,MediaPlayer能正常播放是因为它原生支持接收Content URI,并自动通过ContentResolver读取资源内容。

解决方案

1. 持久化URI访问权限

你通过文件选择器拿到URI之后,需要先向系统申请持久化读权限,避免应用重启后权限失效:

// 拿到URI后立即执行,仅scheme为content的URI需要走该逻辑
if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
    context.contentResolver.takePersistableUriPermission(
        uri,
        Intent.FLAG_GRANT_READ_URI_PERMISSION
    )
}

2. 修改zip打包逻辑,通过流写入压缩包

Zip4j支持直接通过输入流添加文件到压缩包,不需要本地File对象。你可以通过ContentResolver打开Content URI的输入流,再添加到zip包中,同时可以查询Content URI获取文件原名,作为压缩包内的文件名。

修改后的完整代码如下:

fun zipAudios(context: Context, fileUrls: ArrayList<String>): File? {
    val zipfileCreated = createFile(
        getOutputDirectory(context),
        "yyyy-MM-dd-HH-mm-ss-SSS",
        ".zip"
    )
    val contentResolver = context.contentResolver
    // 定义查询列,用于获取音频文件原名
    val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)

    try {
        val zipfile = ZipFile(zipfileCreated, null)
        for (urlStr in fileUrls) {
            val uri = Uri.parse(urlStr)
            // 查询获取文件名
            var fileName = ""
            contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
                if (cursor.moveToFirst()) {
                    fileName = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME))
                }
            }
            // 兜底逻辑,拿不到文件名时生成默认名避免异常
            if (fileName.isBlank()) {
                fileName = "audio_${System.currentTimeMillis()}.mp3"
            }
            val zipParameters = ZipParameters()
            zipParameters.fileNameInZip = fileName
            // 打开输入流写入压缩包
            contentResolver.openInputStream(uri)?.use { inputStream ->
                zipfile.addStream(inputStream, zipParameters)
            }
        }
        return zipfile.file
    } catch (ex: IOException) {
        ex.printStackTrace()
    }
    return null
}
注意事项
  • 不需要申请额外的存储权限,只要是通过系统文件选择器合法拿到的Content URI,申请持久化权限后就可以正常读取
  • 该逻辑兼容Android 10及以上所有版本,targetSdkVersion升级到30+也无需额外修改
  • 代码中用use扩展方法处理流,可以自动关闭资源,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 04:45:06