android10以上 uri转file

android10以后,只需要考虑沙盒里的文件uri和共享文件(匿名uri)的转换,其他类型的,要么转换不成File,要么拿不到,也就不用再考虑了

沙盒里的文件,可以直接转成File使用,共享文件如果要操作,需要先复制到沙盒目录下

kotlin写法

@RequiresApi(Build.VERSION_CODES.Q)
private fun uriToFileQ(context: Context, uri: Uri): File? =
    if (uri.scheme == ContentResolver.SCHEME_FILE)
        uri.toFile()
    else if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
        //把文件保存到沙盒
        val contentResolver = context.contentResolver
        val cursor = contentResolver.query(uri, null, null, null, null)
        cursor?.let {
            if (it.moveToFirst()) {
                val ois = context.contentResolver.openInputStream(uri)
                val displayName =
                    it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                ois?.let {
                    File(
                        context.externalCacheDir!!.absolutePath,
                        "${Random.nextInt(0, 9999)}$displayName"
                    ).apply {
                        val fos = FileOutputStream(this)
                        android.os.FileUtils.copy(ois, fos)
                        fos.close()
                        it.close()
                    }
                }
            } else null

        }

    } else null

 

java写法

    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static File uriToFileApiQ(Uri uri) {
        File file = null;
        //android10以上转换
        if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
            file = new File(uri.getPath());
        } else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
            //把文件复制到沙盒目录
            ContentResolver contentResolver = context.getContentResolver();
            Cursor cursor = contentResolver.query(uri, null, null, null, null);
            if (cursor.moveToFirst()) {
                String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                try {
                    InputStream is = contentResolver.openInputStream(uri);
                    File cache = new File(context.getExternalCacheDir().getAbsolutePath(), Math.round((Math.random() + 1) * 1000) + displayName);
                    FileOutputStream fos = new FileOutputStream(cache);
                    FileUtils.copy(is, fos);
                    file = cache;
                    fos.close();
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }

 

兼容全版本的写法

fun uriToFile(context: Context, uri: Uri) =
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        uriToFileQ(context, uri)
    } else uriToFileN(context, uri)


@RequiresApi(Build.VERSION_CODES.Q)
private fun uriToFileQ(context: Context, uri: Uri): File? =
    if (uri.scheme == ContentResolver.SCHEME_FILE)
        uri.toFile()
    else if (uri.scheme == ContentResolver.SCHEME_CONTENT) {
        //把文件保存到沙盒
        val contentResolver = context.contentResolver
        val cursor = contentResolver.query(uri, null, null, null, null)
        cursor?.let {
            if (it.moveToFirst()) {
                val ois = context.contentResolver.openInputStream(uri)
                val displayName =
                    it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                ois?.let {
                    File(
                        context.externalCacheDir!!.absolutePath,
                        "${Random.nextInt(0, 9999)}$displayName"
                    ).apply {
                        val fos = FileOutputStream(this)
                        android.os.FileUtils.copy(ois, fos)
                        fos.close()
                        it.close()
                    }
                }
            } else null

        }

    } else null

private fun uriToFileN(context: Context, uri: Uri): File? {
    val authority = uri.authority
    val scheme = uri.scheme
    val path = uri.path
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && path != null) {
        val externals = arrayOf("/external", "/external_path")
        externals.forEach {
            if (path.startsWith(it + "/")) {
                val file = File(
                    Environment.getExternalStorageDirectory().absolutePath + path.replace(it, "")
                )
                if (file.exists()) {
                    return file
                }
            }
        }
    }
    if (scheme == ContentResolver.SCHEME_FILE)
        return uri.toFile()
    else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(
            context,
            uri
        )
    ) {
        return if ("com.android.externalstorage.documents" == authority) {
            val docId = DocumentsContract.getDocumentId(uri)
            val split = docId.split(":").toTypedArray()
            val type = split[0]
            if ("primary".equals(type, ignoreCase = true)) {
                return File(
                    Environment.getExternalStorageDirectory()
                        .toString() + "/" + split[1]
                )
            } else {
                val mStorageManager =
                    context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
                val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
                val getVolumeList = mStorageManager.javaClass.getMethod("getVolumeList")
                val getUuid = storageVolumeClazz.getMethod("getUuid")
                val getState = storageVolumeClazz.getMethod("getState")
                val getPath = storageVolumeClazz.getMethod("getPath")
                val isPrimary = storageVolumeClazz.getMethod("isPrimary")
                val isEmulated = storageVolumeClazz.getMethod("isEmulated")
                val result = getVolumeList.invoke(mStorageManager)
                val length = Array.getLength(result)
                for (i in 0 until length) {
                    val storageVolumeElement = Array.get(result, i)
                    val mounted = Environment.MEDIA_MOUNTED == getState.invoke(storageVolumeElement)
                            || Environment.MEDIA_MOUNTED_READ_ONLY == getState.invoke(
                        storageVolumeElement
                    )

                    if (!mounted) continue
                    if (isPrimary.invoke(storageVolumeElement) as Boolean
                        && isEmulated.invoke(storageVolumeElement) as Boolean
                    ) continue

                    val uuid = getUuid.invoke(storageVolumeElement) as String
                    if (uuid == type) {
                        return File(
                            getPath.invoke(storageVolumeElement).toString() + "/" + split[1]
                        )
                    }
                }

            }
            null
        } else if ("com.android.providers.downloads.documents" == authority) {
            val id = DocumentsContract.getDocumentId(uri)
            if (!TextUtils.isEmpty(id)) {
                val contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"),
                    java.lang.Long.valueOf(id)
                )
                return getFileFromUri(context, contentUri)
            }
            null
        }
        else if ("com.android.providers.media.documents" == authority) {
            val docId = DocumentsContract.getDocumentId(uri)
            val split = docId.split(":").toTypedArray()
            val type = split[0]
            val contentUri: Uri
            contentUri = if ("image" == type) {
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI
            } else if ("video" == type) {
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI
            } else if ("audio" == type) {
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
            } else return null
            val selection = "_id=?"
            val selectionArgs = arrayOf(split[1])
            getFileFromUri(context, contentUri, selection, selectionArgs)
        }
        else if (ContentResolver.SCHEME_CONTENT == scheme)
            getFileFromUri(context, uri)
        else
            null

    }

    return null
}


private fun getFileFromUri(
    context: Context, uri: Uri, selection: String? = null,
    selectionArgs: kotlin.Array? = null
): File? =
    context.contentResolver.query(uri, arrayOf("_data"), selection, selectionArgs, null)?.let {
        if (it.moveToFirst()) {
            it.getColumnIndex(MediaStore.Images.Media.DATA).let {index->
                if(index == -1 ) null else File(it.getString(index))
            }
        } else null
    }

 

你可能感兴趣的:(uri转file,anroid11文件操作,android10,文件操作,android11,uri)