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

Kotlin使用ZipFile报错FileNotFoundException:文件不存在

解决Kotlin中用ZipFile读取选择文件时的FileNotFoundException问题

这个问题我之前也碰到过!核心问题是你用ACTION_GET_CONTENT获取的Uri并不是真实的文件系统路径——/document/acc=1;doc=155是Content URI,它指向的是内容提供者管理的资源(比如本地文件、Google Drive文件等),不是本地磁盘上的直接文件路径,所以直接用File(selectedFile!!.path)肯定会抛出文件不存在的异常。

下面给你两种可行的解决方案:

方案一:用ZipInputStream处理(推荐,无需临时文件)

既然我们拿到的是Content URI,直接通过ContentResolver打开输入流,用ZipInputStream来读取ZIP内容就好,不需要依赖真实的本地文件路径:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 111 && resultCode == RESULT_OK) {
        data?.data?.let { uri ->
            // 用use块自动关闭流,避免资源泄漏
            contentResolver.openInputStream(uri)?.use { inputStream ->
                ZipInputStream(inputStream).use { zipStream ->
                    var zipEntry: ZipEntry?
                    // 遍历ZIP里的所有条目
                    while (zipStream.nextEntry.also { zipEntry = it } != null) {
                        zipEntry?.let { entry ->
                            Log.d("ZipInfo", "找到条目:${entry.name}")
                            // 如果需要提取内容,这里可以读取流的内容,比如写入到本地文件
                            // entry.size可以获取条目大小,entry.isDirectory判断是否是文件夹
                        }
                    }
                }
            } ?: run {
                Log.e("ZipError", "无法打开Uri对应的输入流")
            }
        }
    }
}

方案二:复制到临时文件后用ZipFile处理(适合需要随机访问ZIP内容的场景)

如果你确实需要使用ZipFile(比如要随机访问ZIP里的某个文件,而不是顺序遍历),可以把Content URI对应的内容复制到一个应用缓存目录下的临时文件,再用ZipFile操作这个临时文件:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 111 && resultCode == RESULT_OK) {
        data?.data?.let { uri ->
            try {
                // 在应用缓存目录创建临时ZIP文件,无需额外权限
                val tempZipFile = File.createTempFile("temp_zip", ".zip", cacheDir)
                
                // 把Content URI的内容复制到临时文件
                contentResolver.openInputStream(uri)?.use { inputStream ->
                    tempZipFile.outputStream().use { outputStream ->
                        inputStream.copyTo(outputStream)
                    }
                }
                
                // 现在可以正常使用ZipFile了
                ZipFile(tempZipFile).use { zipFile ->
                    val entries = zipFile.entries()
                    while (entries.hasMoreElements()) {
                        val entry = entries.nextElement()
                        Log.d("ZipEntry", "条目名称:${entry.name},大小:${entry.size}")
                        // 这里可以做随机访问,比如直接获取某个条目的输入流:zipFile.getInputStream(entry)
                    }
                }
                
                // 用完临时文件后删除,避免占用空间
                tempZipFile.delete()
            } catch (e: IOException) {
                e.printStackTrace()
                Log.e("ZipError", "处理ZIP文件失败:${e.message}")
            }
        }
    }
}

注意事项

  • 一定要用use块包裹流和ZipFile,Kotlin会自动帮你关闭资源,防止内存泄漏。
  • 不要尝试手动解析Content URI的path字段,不同内容提供者的格式差异很大,完全不可靠。
  • 临时文件存在应用的cacheDir里,系统会在空间不足时自动清理,也不会涉及外部存储权限问题。

内容的提问来源于stack exchange,提问作者Николай Никульцев

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:42:36