如何在Android Q中获取Android文档目录的路径?

3

我很难找到一个清晰的答案来回答这个问题。我知道它涉及使用媒体存储,但我无法完全理解。

谢谢。

编辑:如果有帮助的话,我目前正在使用Pixel 2。

2个回答

5
如果您的目标是针对Android 11 API,则无法直接访问文件路径,因为在API 30(Android R)中有许多限制。由于在Android 10(API 29)中引入了scoped storage API,因此存储现在被分为scoped storage(私有存储)和shared storage(公共存储)。Scoped storage是一种只能访问在您的scoped storage目录中创建的文件(即/ Android / data /或/ Android / media /)的文件类型。您无法从共享存储(即内部存储器/外部SD卡存储器等)访问文件。

共享存储再次进一步分为媒体和下载集合。媒体收藏存储图像、音频和视频文件。下载集合将管理非媒体文件。

要详细了解scoped storage和shared storage,请参阅此链接- Android 10和Android 11中的Scoped Storage

要获取文档目录路径,我创建了URI utils类,该类将从URI获取文件的路径。

    import android.content.ContentUris
    import android.content.Context
    import android.database.Cursor
    import android.net.Uri
    import android.os.Build
    import android.os.Environment
    import android.provider.DocumentsContract
    import android.provider.MediaStore
    import android.provider.OpenableColumns
    import android.util.Log
    import android.widget.Toast
    import java.io.File
    import java.io.FileOutputStream
    
    class UriPathUtils
    {
        fun getRealPathFromURI(context: Context, uri: Uri): String? {
            when {
                // DocumentProvider
                DocumentsContract.isDocumentUri(context, uri) -> {
                    when {
                        // ExternalStorageProvider
                        isExternalStorageDocument(uri) -> {
                            //Toast.makeText(context, "From Internal & External Storage dir", Toast.LENGTH_SHORT).show()
                            val docId = DocumentsContract.getDocumentId(uri)
                            val split = docId.split(":").toTypedArray()
                            val type = split[0]
                            // This is for checking Main Memory
                            return if ("primary".equals(type, ignoreCase = true)) {
                                if (split.size > 1) {
                                    Environment.getExternalStorageDirectory().toString() + "/" + split[1]
                                } else {
                                    Environment.getExternalStorageDirectory().toString() + "/"
                                }
                                // This is for checking SD Card
                            } else {
                                "storage" + "/" + docId.replace(":", "/")
                            }
                        }
                        isDownloadsDocument(uri) -> {
                            //Toast.makeText(context, "From Downloads dir", Toast.LENGTH_SHORT).show()
                            val fileName = getFilePath(context, uri)
                            if (fileName != null) {
                                return Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName
                            }
                            var id = DocumentsContract.getDocumentId(uri)
                            if (id.startsWith("raw:")) {
                                id = id.replaceFirst("raw:".toRegex(), "")
                                val file = File(id)
                                if (file.exists()) return id
                            }
                            val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id))
                            return getDataColumn(context, contentUri, null, null)
                        }
                        isMediaDocument(uri) -> {
                            //Toast.makeText(context, "From Documents dir", Toast.LENGTH_SHORT).show()
                            val docId = DocumentsContract.getDocumentId(uri)
                            val split = docId.split(":").toTypedArray()
                            val type = split[0]
                            var contentUri: Uri? = null
                            when (type) {
                                "image" -> {
                                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
                                }
                                "video" -> {
                                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
                                }
                                "audio" -> {
                                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
                                }
                                else -> {
                                    //non-media files i.e documents and other files
                                    contentUri = MediaStore.Files.getContentUri("external")
                                    val selection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                                        MediaStore.MediaColumns.RELATIVE_PATH + "=?"
                                    } else "_id=?"
                                    val selectionArgs = arrayOf(Environment.DIRECTORY_DOCUMENTS)
                                    return getMediaDocumentPath(context, contentUri,selection,selectionArgs)
                                }
                            }
                            val selection = "_id=?"
                            val selectionArgs = arrayOf(split[1])
                            return getDataColumn(context, contentUri, selection, selectionArgs)
                        }
                        isGoogleDriveUri(uri) -> {
                            Toast.makeText(context, "From Google Drive", Toast.LENGTH_SHORT).show()
                            return getDriveFilePath(uri, context)
                        }
                        /*else -> {
                            Toast.makeText(context, "Unknown Directory", Toast.LENGTH_SHORT).show()
                        }*/
                    }
                }
                "content".equals(uri.scheme, ignoreCase = true) -> {
                    //Toast.makeText(context, "From Content Uri", Toast.LENGTH_SHORT).show()
                    // Return the remote address
                    return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn(context, uri, null, null)
                }
                "file".equals(uri.scheme, ignoreCase = true) -> {
                    //Toast.makeText(context, "From File Uri", Toast.LENGTH_SHORT).show()
                    return uri.path
                }
            }
            return null
        }
    
        private fun getDataColumn(context: Context, uri: Uri?, selection: String?, selectionArgs: Array<String>?): String? {
            var cursor: Cursor? = null
            val column = "_data"
            val projection = arrayOf(column)
            try {
                if (uri == null) return null
                cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
                if (cursor != null && cursor.moveToFirst()) {
                    val index = cursor.getColumnIndexOrThrow(column)
                    return cursor.getString(index)
                }
            } finally {
                cursor?.close()
            }
            return null
        }
    
        private fun getMediaDocumentPath(context: Context, uri: Uri?,selection: String?, selectionArgs: Array<String>?): String? {
            var cursor: Cursor? = null
            val column = "_data"
            val projection = arrayOf(column)
            try {
                if (uri == null) return null
                cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
                if (cursor != null && cursor.moveToFirst()) {
                    val index = cursor.getColumnIndexOrThrow(column)
                    //Toast.makeText(context, "From Media Document --- Non Media Path ${cursor.getString(index)} ", Toast.LENGTH_SHORT).show()
                    return cursor.getString(index)
                }
            } finally {
                cursor?.close()
            }
            return null
        }
    
        private fun getFilePath(context: Context, uri: Uri?): String? {
            var cursor: Cursor? = null
            val projection = arrayOf(MediaStore.MediaColumns.DISPLAY_NAME)
            try {
                if (uri == null) return null
                cursor = context.contentResolver.query(uri, projection, null, null,
                    null)
                if (cursor != null && cursor.moveToFirst()) {
                    val index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
                    return cursor.getString(index)
                }
            } finally {
                cursor?.close()
            }
            return null
        }
    
        private fun getDriveFilePath(uri: Uri, context: Context): String? {
            val returnCursor = context.contentResolver.query(uri, null, null, null, null)
            val nameIndex = returnCursor!!.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            val sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE)
            returnCursor.moveToFirst()
            val name = returnCursor.getString(nameIndex)
            val size = returnCursor.getLong(sizeIndex).toString()
            val file = File(context.cacheDir, name)
            try {
                val inputStream = context.contentResolver.openInputStream(uri)
                val outputStream = FileOutputStream(file)
                var read = 0
                val maxBufferSize = 1 * 1024 * 1024
                val bytesAvailable = inputStream!!.available()
    
                //int bufferSize = 1024;
                val bufferSize = Math.min(bytesAvailable, maxBufferSize)
                val buffers = ByteArray(bufferSize)
                while (inputStream.read(buffers).also { read = it } != -1) {
                    outputStream.write(buffers, 0, read)
                }
                Log.e("File Size", "Size " + file.length())
                inputStream.close()
                outputStream.close()
                Log.e("File Path", "Path " + file.path)
                Log.e("File Size", "Size " + file.length())
            } catch (e: Exception) {
                Log.e("Exception", e.message!!)
            }
            return file.path
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         */
        private fun isExternalStorageDocument(uri: Uri): Boolean {
            return "com.android.externalstorage.documents" == uri.authority
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         */
        private fun isDownloadsDocument(uri: Uri): Boolean {
            return "com.android.providers.downloads.documents" == uri.authority
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         */
        private fun isMediaDocument(uri: Uri): Boolean {
            return "com.android.providers.media.documents" == uri.authority
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is Google Photos.
         */
        private fun isGooglePhotosUri(uri: Uri): Boolean {
            return "com.google.android.apps.photos.content" == uri.authority
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is Google Photos.
         */
        private fun isGoogleDriveUri(uri: Uri): Boolean {
            return "com.google.android.apps.docs.storage" == uri.authority || "com.google.android.apps.docs.storage.legacy" == uri.authority
        }
}

这个工具类能够帮助你获取文件路径,只需要调用这一行代码即可。

contentUri.let { UriPathUtils().getRealPathFromURI(this, it).toString() }

Cheers...!


1
Uri contentUri = MediaStore.Files.getContentUri("external");

String selection = MediaStore.MediaColumns.RELATIVE_PATH + "=?";

String[] selectionArgs = new String[]{Environment.DIRECTORY_DOCUMENTS};

Cursor cursor = getContentResolver().query(contentUri, null, selection, selectionArgs, null);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接