Kotlin安卓APP选取音频上传报ENOENT无此文件或目录错误
错误原因
你选取文件后拿到的data.data是安卓的Content URI,不是本地文件的真实存储路径。直接调用URI的path属性拿到的/document/primary:Music/Track28.mp3只是URI的路径标识,不是系统可直接访问的本地文件路径,用它构造File对象自然会触发文件不存在的ENOENT错误。
修复方案
不要直接将URI转File,而是通过ContentResolver读取URI对应的文件流,写入App私有缓存目录生成临时文件后再上传,示例代码如下:
首先实现URI转缓存文件的工具方法:
// 通过Content URI获取可用的缓存文件 fun getFileFromUri(context: Context, uri: Uri): File? { val fileName = getFileName(context, uri) ?: return null val tempFile = File(context.cacheDir, fileName) return try { context.contentResolver.openInputStream(uri)?.use { input -> tempFile.outputStream().use { output -> input.copyTo(output) } } tempFile } catch (e: Exception) { e.printStackTrace() null } } // 从URI中读取文件名 fun getFileName(context: Context, uri: Uri): String? { var fileName: String? = null val cursor = context.contentResolver.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null) cursor?.use { if (it.moveToFirst()) { fileName = it.getString(0) } } return fileName }
修改你的上传逻辑:
// 替换掉原来直接构造File的代码 val audioFile = getFileFromUri(requireContext(), newAudio!!) ?: run { Toast.makeText(requireContext(), "读取音频文件失败", Toast.LENGTH_SHORT).show() return // 此处根据你的代码实际触发位置调整返回逻辑 } val requestFile = RequestBody.create(MediaType.parse("audio/mpeg"), audioFile) val bodyFile = MultipartBody.Part.createFormData("file", audioFile.name, requestFile) // 原有Retrofit上传逻辑保持不变即可
注意事项
- 上传完成后如果不需要留存本地文件,可以调用
audioFile.delete()删除缓存文件,避免占用存储 - 提前确认你已经动态申请了对应版本的存储权限:安卓13+需要
READ_MEDIA_AUDIO权限,安卓12及更低版本需要READ_EXTERNAL_STORAGE权限
内容的提问来源于stack exchange,提问作者Daniil Andreev
相关产品推荐
相关产品推荐

