返回

如何轻松从Uri中获取文件的绝对路径?

java

## 如何从 Uri 中获取文件的绝对路径

### 问题概述

在 Android 开发中,Uri 广泛用于引用内容提供商中的文件。然而,有时我们需要获取文件的绝对路径,以进一步对其进行操作。本文将深入探讨如何从 Uri 内容中获取文件的绝对路径,帮助你解决遇到的难题。

### 获取绝对路径的步骤

要从 Uri 中获取文件的绝对路径,请遵循以下步骤:

  1. 确定 Uri 类型: 首先,你需要确定 Uri 的类型。有三种常见的 Uri 类型:文件 Uri、内容 Uri 和文档 Uri。

  2. 文件 Uri: 对于文件 Uri,路径可以从 Uri 中直接获取。只需使用 getScheme() 方法来获取 Uri 的协议。如果协议是 “file”,则可以使用 getPath() 方法获取路径。

  3. 内容 Uri: 对于内容 Uri,你需要使用 ContentResolver 来查询内容提供商。使用 query() 方法,指定 Uri 和投影(要获取的列)。将投影设置为 MediaStore.Images.Media.DATA,这将返回文件的绝对路径。

  4. 文档 Uri: 文档 Uri 是 Android 4.4(KitKat)中引入的一种新 Uri 类型。对于文档 Uri,你需要使用 DocumentsContract 类。使用 isDocumentUri() 方法来检查 Uri 是否为文档 Uri。如果是,则使用 getDocumentId() 方法获取文档 ID。使用 split() 方法将文档 ID 拆分为两部分,第一部分是文档类型,第二部分是文档 ID。根据文档类型,你可以使用不同的方法获取绝对路径。

### 示例代码

下面是获取文件绝对路径的示例代码:

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

public class FileUtils {

    public static String getFilePathFromUri(Context context, Uri uri) {
        String path = null;
        if (uri.getScheme().equals("file")) {
            path = uri.getPath();
        } else if (uri.getScheme().equals("content")) {
            if (isDocumentUri(context, uri)) {
                String documentId = DocumentsContract.getDocumentId(uri);
                String[] parts = documentId.split(":");
                String type = parts[0];
                String realDocId = parts[1];
                if ("image".equalsIgnoreCase(type)) {
                    path = getFilePathFromImageUri(context, uri, realDocId);
                } else if ("video".equalsIgnoreCase(type)) {
                    path = getFilePathFromVideoUri(context, uri, realDocId);
                } else if ("audio".equalsIgnoreCase(type)) {
                    path = getFilePathFromAudioUri(context, uri, realDocId);
                }
            } else {
                path = getFilePathFromContentUri(context, uri);
            }
        }
        return path;
    }

    private static String getFilePathFromImageUri(Context context, Uri uri, String realDocId) {
        String[] projection = {MediaStore.Images.Media.DATA};
        String selection = MediaStore.Images.Media._ID + " = ?";
        String[] selectionArgs = {realDocId};
        Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                path = cursor.getString(columnIndex);
            }
            cursor.close();
        }
        return path;
    }

    private static String getFilePathFromVideoUri(Context context, Uri uri, String realDocId) {
        String[] projection = {MediaStore.Video.Media.DATA};
        String selection = MediaStore.Video.Media._ID + " = ?";
        String[] selectionArgs = {realDocId};
        Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndex(MediaStore.Video.Media.DATA);
                path = cursor.getString(columnIndex);
            }
            cursor.close();
        }
        return path;
    }

    private static String getFilePathFromAudioUri(Context context, Uri uri, String realDocId) {
        String[] projection = {MediaStore.Audio.Media.DATA};
        String selection = MediaStore.Audio.Media._ID + " = ?";
        String[] selectionArgs = {realDocId};
        Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
                path = cursor.getString(columnIndex);
            }
            cursor.close();
        }
        return path;
    }

    private static String getFilePathFromContentUri(Context context, Uri uri) {
        String[] projection = {MediaStore.MediaColumns.DATA};
        Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                int columnIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
                path = cursor.getString(columnIndex);
            }
            cursor.close();
        }
        return path;
    }

    private static boolean isDocumentUri(Context context, Uri uri) {
        return DocumentsContract.isDocumentUri(context, uri);
    }
}

### 额外提示

  • 外部存储访问权限: 如果文件位于外部存储卡上,请确保你有访问外部存储的权限。
  • 其他应用程序的文件访问权限: 如果文件来自其他应用程序,请确保你有读取该应用程序文件的权限。

### 结论

掌握了从 Uri 内容中获取文件的绝对路径的方法,你将能够更灵活地处理文件,解锁更多操作的可能性。希望本指南能帮助你顺利解决相关难题,提升你的 Android 开发技能。

### 常见问题解答

  1. 如何检查 Uri 是否为文件 Uri?

    • 检查 Uri 的协议是否为 "file"。
  2. 如何使用文档 Uri 获取绝对路径?

    • 使用 DocumentsContract 类中的 getDocumentId()split() 方法解析文档 ID,然后根据文档类型使用相应的方法获取路径。
  3. 能否获取外部存储卡上文件的绝对路径?

    • 是的,只要你有访问外部存储的权限。
  4. 如何处理来自其他应用程序的文件?

    • 确保你有读取该应用程序文件的权限,然后使用适当的方法获取路径。
  5. 为什么我获取的绝对路径为 null?

    • 可能是因为 Uri 无效或你没有必要的权限。仔细检查 Uri 并确保你有访问权限。