当前位置: 首页 > news >正文

通过uri获取文件路径手机适配

青铜版本

  return contentResolver.query(this, arrayOf(MediaStore.MediaColumns.DATA), null, null).let {
        if (it?.moveToFirst() == true) {
            val columnIndex = it.getColumnIndex(MediaStore.MediaColumns.DATA)
            val path = it.getString(columnIndex)
            it.close()
            return path
        }
        ""
    }

在firebase上发现很多异常奔溃日志,部分手机获取到的 path 是空的,也就是说没有_data字段

其实有的手机通过选择图片或者文件后返回的uri并不一定是媒体uri,也可能是document uri,造成这个时候直接通过 uri查询,找不到_data字段,需要将 document uri中分离出类型和id,在拼凑成新的uri,在通过contentprovider查询,才可以查出 _data字段中真正的路径

//如果是Document类型的URI,需要进行转换
private fun getPathFromDocumentUri(uri: Uri): String? {
    val isDocumentUri = DocumentsContract.isDocumentUri(BaseApplication.instance, uri)
    if (isDocumentUri) {
        val docId = DocumentsContract.getDocumentId(uri)
        val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        val type = split[0] // "image"
        val id = split[1] // "1044024"
        var quaryUri: Uri? = null
        if ("image".equals(type)) {
            quaryUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        } else if ("video".equals(type)) {
            quaryUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        } else if ("audio".equals(type)) {
            quaryUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        }

        LogUtils.d("linlian quaryUri=$quaryUri")
        quaryUri?.let {
            val projection = arrayOf(MediaStore.Images.Media.DATA,MediaStore.Images.Media._ID)
            BaseApplication.instance.contentResolver.query(
                quaryUri,
                projection,
                MediaStore.Images.Media._ID + "=?",
                arrayOf<String>(id),
                null
            )?.use {cursor ->

                val columnNames = cursor.columnNames
                LogUtils.d("linlian ", "URI: $uri")
                LogUtils.d("linlian ", "Total columns: ${columnNames.size}")

                // 遍历每一行
                while (cursor.moveToNext()) {
//                    val rowData = StringBuilder()
                    // 遍历每一列
//                    for (columnName in columnNames) {
//                        val columnIndex = cursor.getColumnIndex(columnName)
//                        if (columnIndex == -1) {
//                            rowData.append("$columnName: [COLUMN_NOT_FOUND]\n")
//                            continue
//                        }
//
//                        val value = when (cursor.getType(columnIndex)) {
//                            Cursor.FIELD_TYPE_NULL -> "NULL"
//                            Cursor.FIELD_TYPE_INTEGER -> cursor.getLong(columnIndex)
//                            Cursor.FIELD_TYPE_FLOAT -> cursor.getDouble(columnIndex)
//                            Cursor.FIELD_TYPE_STRING -> cursor.getString(columnIndex)
//                            Cursor.FIELD_TYPE_BLOB -> "BLOB (${cursor.getBlob(columnIndex)?.size ?: 0} bytes)"
//                            else -> "UNKNOWN_TYPE"
//                        }
//                        rowData.append("$columnName: $value\n")
//                    }
//                    LogUtils.d("linlian", "Row ${cursor.position}:\n$rowData")

                    val index= cursor.getColumnIndex(MediaStore.Images.Media.DATA)
                    if(index!=-1){
                        val path = cursor.getString(index)
                        LogUtils.d("linlian", "!!!!!!!!!!$path")
                        return path
                    }
                    LogUtils.d("linlian", "!!!!!!!!!!$index")
                }
                return null
            }

        }

    }
    return null
}

但是根据文档其实Android 10 之后是有新的字段,但是手机厂商众多,实现方式不一,还是找不到path怎么办,官方是说可以从 RELATIVE_PATH获取路径

contentResolver.query(uri, projection, null, null, null).use { cursor ->
                if (cursor != null && cursor.moveToFirst()) {
                    // 获取文件名
                    val nameIndex: Int = cursor.getColumnIndex(
                        if (isImage) MediaStore.Images.Media.DISPLAY_NAME else MediaStore.Video.Media.DISPLAY_NAME
                    )
                    val displayName: String? =
                        if ((nameIndex != -1)) cursor.getString(nameIndex) else null

                    // 获取相对路径(可能为 null)
                    val pathIndex: Int = cursor.getColumnIndex(
                        if (isImage) MediaStore.Images.Media.RELATIVE_PATH else MediaStore.Video.Media.RELATIVE_PATH
                    )
                    val relativePath: String? =
                        if ((pathIndex != -1)) cursor.getString(pathIndex) else null
                    LogUtils.d("linlian getPathFromRelativeColumn displayName=$displayName,relativePath=$relativePath")
                    // 生成最终路径
                    return buildPathForAndroidQ(displayName, relativePath)
                }
            }

如果以上都找不到path 怎么办呢

那最后的方式是,通过uri拷贝一份文件到应用目录,不过用完记得删除

fun copyFileFromUri(context: Context, uri: Uri, destFileName: String): File? {
    return try {
        // 打开输入流
        val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
        if (inputStream == null) {
            return null
        }

        // 目标文件:保存在 app 的 filesDir 目录
        val destFile = File(context.filesDir, destFileName)
        val outputStream: OutputStream = FileOutputStream(destFile)

        // 拷贝数据
        val buffer = ByteArray(4096)
        var bytesRead: Int
        while (inputStream.read(buffer).also { bytesRead = it } != -1) {
            outputStream.write(buffer, 0, bytesRead)
        }

        // 关闭流
        inputStream.close()
        outputStream.close()

        destFile
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}





相关文章:

  • 10套关于RoboCup机器人世界杯中国赛-创客AI编程挑战赛的相关题目(由deepseek生成)
  • GGML源码逐行调试(上)
  • Openlayers:flat样式介绍
  • Ubuntu 服务器版本 设置socket服务(Python)
  • SpringBoot3.0 +GraalVM21 + Docker 打包成可执行文件
  • 【算法】快速排序
  • leetcode 279. Perfect Squares
  • SQL ⑦-索引
  • 【Qt】【第三方库】spdlog日志模块的使用
  • PostgreSQL与PostGIS版本对应
  • codeforces B2. The Strict Teacher
  • 代码学习总结(一)
  • 目标追踪Hyperspectral Adapter for Object Tracking based on Hyperspectral Video
  • 项目二 使用miniedit创建拓扑
  • Vue 项目中 package.json 文件的深度解析
  • 列出一个目录中所有文件的名字
  • 【问题记录】记录2个安装Centos/Anolis系统卡死在安装包阶段的问题?(硬盘分区?换设备)
  • RCE之无字母数字RCE
  • SLAM(七)-卡尔曼滤波
  • Servlet、HTTP与Spring Boot Web全面解析与整合指南
  • 银行网站建设/海南百度推广总代理
  • 厦门网站改版/网络广告代理
  • 上海网站建设网页制作邢台/湖南专业的关键词优化
  • 邢台做网站优化哪儿好/广州百度推广客服电话
  • 新疆网站开发报价/黄页88网络营销宝典
  • 网站建设与维护作业/如何做好网上销售