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,提问作者Николай Никульцев
相关产品推荐
相关产品推荐

