萌萌の初音
萌萌の初音
发布于 2020-12-27 / 1414 阅读
0

Android 10以上文件读取受限的解决方案

  1. 可以将文件复制到app的沙盒目录中
    fun uriToFileCache(context: Context, uri: Uri): File {
        val file = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            File("${context.dataDir.path}/tmp/${getUriFileName(uri,context)}")
        } else File("${context.filesDir.path.substring(0, context.filesDir.path.lastIndexOf("/"))}/tmp/${getUriFileName(uri,context)}")
        if (!file.exists()) {
            file.parentFile.mkdirs()
            val ois = context.contentResolver.openInputStream(uri)
            val fos = FileOutputStream(file)
            val buffer = ByteArray(1024)
            var byteCount = 0
            while (ois?.read(buffer).also {
                        if (it != null) {
                            byteCount = it
                        }
                    } != -1) {
                fos.write(buffer, 0, byteCount)
            }
            fos.flush()
            fos.close()
            ois?.close()
        }
        return file
    }

  1. getUriFileName方法为通过Uri获取文件名,Uri不能直接获取文件名
    fun getUriFileName(uri:Uri,context: Context):String{
        return when(uri.scheme){
            ContentResolver.SCHEME_CONTENT->{
                val cursor = context.contentResolver.query(uri, null, null, null, null, null)
                cursor?.let {
                    it.moveToFirst()
                    val displayName = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                    cursor.close()
                    displayName
                }?:"${System.currentTimeMillis()}.${MimeTypeMap.getSingleton().getExtensionFromMimeType(context.contentResolver.getType(uri))}}"

            }
            else -> "${System.currentTimeMillis()}.${MimeTypeMap.getSingleton().getExtensionFromMimeType(context.contentResolver.getType(uri))}}"
        }
    }

3.如果你是用的ContentResolver方法调取的文件信息,可以通过以下方式获取文件名

    fun getImageFileName(context: Context, uri: Uri?): String? {
        CursorLoader(context, uri!!, arrayOf(MediaStore.Images.Media.DATA), null, null, null).loadInBackground().use {
            it!!.moveToNext()
            val path = it.getString(it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
            return if (path != null && !TextUtils.equals(path, "")) path.substring(path.lastIndexOf("/") + 1) else "xxx.jpg"
        }
    }

4.把你沙盒里的图片路径转换为Uri(其它类型的文件可以同理转换)

    fun getImageContentUri(context: Context, path: String): Uri? {
        CursorLoader(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, arrayOf(MediaStore.Images.Media._ID), MediaStore.Images.Media.DATA + "=? ", arrayOf(path), null).loadInBackground().use {
            return if (it != null && it.moveToFirst()) {
                val id = it.getInt(it.getColumnIndex(MediaStore.MediaColumns._ID))
                val baseUri = Uri.parse("content://media/external/images/media")
                Uri.withAppendedPath(baseUri, "" + id)
            } else {
                // 如果图片不在手机的共享图片数据库,就先把它插入。
                if (File(path).exists()) {
                    val values = ContentValues()
                    values.put(MediaStore.Images.Media.DATA, path)
                    context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
                } else {
                    null
                }
            }
        }
    }

详细代码可以进入我的代码仓库里查看哦~指路链接android 10以上文件操作