在Android Jetpack Compose中加载存储Zip文件遇文件不存在问题求助
问题解决:Content URI转File导致的FileNotFoundException
错误原因
你通过ActivityResultContracts.GetContent()获取的是Content URI(示例中的content://com.android.providers.downloads.documents/document/raw:/storage/emulated/0/Download/images.zip),这类URI并非本地文件系统的真实路径,直接用uri.path创建File对象必然找不到文件——因为/document/raw:/storage/emulated/0/Download/images.zip根本不是合法的文件系统路径。
解决方案
放弃直接用File处理Content URI,改用ContentResolver获取文件输入流,通过ZipInputStream读取Zip内容,同时将解压后的文件存到应用私有目录,避免权限问题。
修改后的代码
- 更新Composable,传入Context并限制文件选择类型为Zip:
@Composable fun Content(paddingValues: PaddingValues){ val context = LocalContext.current val fileSearch= rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) { openFile(it, context) } Button(onClick = { fileSearch.launch("application/zip") }) { Text("Search Zip File") } }
- 重写
openFile函数,用ContentResolver处理URI:
fun openFile(uri: Uri?, context: Context) { uri ?: return // 通过ContentResolver获取Zip文件的输入流 context.contentResolver.openInputStream(uri)?.use { inputStream -> ZipInputStream(inputStream).use { zipStream -> var entry: ZipEntry? = zipStream.nextEntry // 用应用私有缓存目录存放解压后的图片,避免权限问题 val outputDir = context.cacheDir while (entry != null) { // 只处理文件,跳过目录项 if (!entry.isDirectory) { val outputFile = File(outputDir, entry.name) // 创建必要的父目录 outputFile.parentFile?.mkdirs() // 将Zip中的文件写入本地 outputFile.outputStream().use { outputStream -> zipStream.copyTo(outputStream) } // 此处可收集outputFile的路径,后续在LazyColumn中加载展示 } zipStream.closeEntry() entry = zipStream.nextEntry } } } }
额外注意事项
- 权限问题:Android 11+的Scoped Storage机制下,使用
GetContent()无需申请WRITE_EXTERNAL_STORAGE权限,因为文件写入的是应用私有目录,系统默认允许访问。 - 文件过滤:将
launch("*/*")改为launch("application/zip"),可让文件选择器只显示Zip文件,提升用户体验。 - 性能优化:若Zip文件较大,建议在协程中执行解压操作,避免阻塞主线程;定期清理缓存目录,防止占用过多存储。
内容的提问来源于stack exchange,提问作者Victor Ortiz
相关产品推荐
相关产品推荐

