如何用Kotlin将Android相机拍摄的临时图片移动到SD卡
报错根本原因
- 你拿到的
content://开头的URI是ContentProvider提供的共享媒体标识符,不是本地文件的绝对路径,直接通过File(uri.path)构造文件对象访问必然会报文件不存在错误,这是核心问题。 - 可移动SD卡的路径不固定,不同设备的卷标(即你提到的E534-12F6类标识符)存在差异,硬编码路径必然适配失败,必须通过系统API动态获取SD卡路径。
- 你当前的
provider_paths.xml配置没有问题,不需要修改。
可行实现方案
前置权限配置
在AndroidManifest.xml中添加存储权限适配,如果你将图片保存到SD卡的应用专属目录(无需用户授权,所有Android版本通用),仅需配置:
<!-- 仅Android 9及以下需要,应用专属目录不需要动态申请 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
核心实现代码
1. 动态获取SD卡应用专属目录
// 返回SD卡上当前应用的专属存储目录,无SD卡则返回null fun getSDCardAppDir(context: Context): File? { val externalDirs = context.getExternalFilesDirs(null) // 数组第一个元素为内置存储目录,长度>=2时第二个元素为可移动SD卡目录 return if (externalDirs.size >= 2) externalDirs[1] else null }
2. 实现Content URI到SD卡文件的复制逻辑
不要直接使用文件移动API,通过ContentResolver读取临时文件的输入流写入SD卡目标文件,稳定性更高:
fun saveTmpImageToSDCard(context: Context, tmpImageUri: Uri, targetFileName: String): File? { return try { // 优先存SD卡,无SD卡则 fallback 到内置存储 val saveDir = getSDCardAppDir(context) ?: context.getExternalFilesDir(null) ?: return null val targetFile = File(saveDir, targetFileName) // 从临时URI读取流写入目标文件 context.contentResolver.openInputStream(tmpImageUri)?.use { inputStream -> FileOutputStream(targetFile).use { outputStream -> inputStream.copyTo(outputStream) } } // 保存成功后主动删除临时缓存文件,不需要依赖deleteOnExit() context.contentResolver.delete(tmpImageUri, null, null) targetFile } catch (e: Exception) { e.printStackTrace() null } }
3. 调用示例
latestTmpUri?.let { uri -> // 自定义保存的文件名,可按业务需求修改 val savedFile = saveTmpImageToSDCard( context = this, tmpImageUri = uri, targetFileName = "captured_${System.currentTimeMillis()}.png" ) if (savedFile != null) { // 保存成功,将savedFile.absolutePath写入CSV文件即可 } }
内容的提问来源于stack exchange,提问作者Thomas Schulze
相关产品推荐
相关产品推荐

