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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 13:36:10