android通过Uri.getPath()获取真实路径

dav*_*avs 99 android image-gallery

我正试图从画廊获取图像.

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode );
Run Code Online (Sandbox Code Playgroud)

从这个活动返回后,我有一个包含Uri的数据.看起来像:

content://media/external/images/1
Run Code Online (Sandbox Code Playgroud)

如何将此路径转换为真实路径(就像' /sdcard/image.png')?

谢谢

ces*_*rds 188

这就是我做的:

Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));
Run Code Online (Sandbox Code Playgroud)

和:

private String getRealPathFromURI(Uri contentURI) {
    String result;
    Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
    if (cursor == null) { // Source is Dropbox or other similar local file path
        result = contentURI.getPath();
    } else { 
        cursor.moveToFirst(); 
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
        result = cursor.getString(idx);
        cursor.close();
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

注意:managedQuery()方法已弃用,因此我不使用它.

最后编辑:改进.我们应该关闭光标!!

  • 如果有人还有问题,那么这对我有帮助:[链接](http://hmkcode.com/android-display-selected-image-and-its-real-path/) (30认同)
  • **错误**确保Cursor在从中访问数据之前已正确初始化..检查API 19 (13认同)
  • 嗨@ m3n0R,在Moto G中,MediaStore.Images.ImageColumns.DATA列根本不存在.如何在没有此列的情况下获取图像? (6认同)
  • MediaStore.Images.ImageColumns.DATA 已弃用 (4认同)
  • 无法从 CursorWindow 读取第 0 行、第 -1 行。在访问 Cursor 中的数据之前,确保它已正确初始化。 (3认同)
  • 崩溃:java.lang.IllegalStateException:无法从 CursorWindow 读取第 0 行、第 -1 行。在访问 Cursor 中的数据之前,确保它已正确初始化。 (2认同)

mol*_*arm 54

你真的有必要获得物理路径吗?
例如,ImageView.setImageURI()并且ContentResolver.openInputStream()允许你访问一个文件的内容,不知道它的真实路径.

  • 抱歉,如果我想将此图像转换为文件,而无法获得真实路径如何操作? (6认同)
  • 物理路径可以访问文件名和扩展名.在文件上传的情况下. (6认同)

lui*_*etx 19

@Rene Juuse - 上面的评论...感谢您的链接!

.获取真实路径的代码从一个SDK到另一个SDK有点不同,所以下面我们有三种处理不同SDK的方法.

getRealPathFromURI_API19():返回API 19(或更高版本但尚未测试)的实际路径getRealPathFromURI_API11to18():将API 11的实际路径返回到API 18 getRealPathFromURI_below11():返回11以下API的实际路径

public class RealPathUtil {

@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri){
    String filePath = "";
    String wholeID = DocumentsContract.getDocumentId(uri);

     // Split at colon, use second item in the array
     String id = wholeID.split(":")[1];

     String[] column = { MediaStore.Images.Media.DATA };     

     // where id is equal to             
     String sel = MediaStore.Images.Media._ID + "=?";

     Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                               column, sel, new String[]{ id }, null);

     int columnIndex = cursor.getColumnIndex(column[0]);

     if (cursor.moveToFirst()) {
         filePath = cursor.getString(columnIndex);
     }   
     cursor.close();
     return filePath;
}


@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
      String[] proj = { MediaStore.Images.Media.DATA };
      String result = null;

      CursorLoader cursorLoader = new CursorLoader(
              context, 
        contentUri, proj, null, null, null);        
      Cursor cursor = cursorLoader.loadInBackground();

      if(cursor != null){
       int column_index = 
         cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
       cursor.moveToFirst();
       result = cursor.getString(column_index);
      }
      return result;  
}

public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){
           String[] proj = { MediaStore.Images.Media.DATA };
           Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
           int column_index
      = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
           cursor.moveToFirst();
           return cursor.getString(column_index);
}
Run Code Online (Sandbox Code Playgroud)

字体:http://hmkcode.com/android-display-selected-image-and-its-real-path/


2016年3月更新

要修复图像路径的所有问题,我尝试创建自定义图库作为Facebook和其他应用程序.这是因为你可以只使用本地文件(真实文件,而不是虚拟或临时文件),我解决了这个库的所有问题.

https://github.com/nohana/Laevatein (这个图书馆是从相机拍照或从画廊中选择,如果你从画廊中选择他有一个带有相册的抽屉,只显示本地文件)

  • 惊人的!终于有真正有效的东西了。找这个很久了。谢谢。 (2认同)

Jai*_*oni 14

注意这是@ user3516549答案的改进,我在Android 6.0的 Moto G3上检查了
我有这个问题,所以我尝试了@ user3516549的答案,但在某些情况下它没有正常工作.我发现在Android 6.0(或更高版本)中,当我们启动图库图像选择意图时,将打开一个屏幕,显示最近的图像,当用户从此列表中选择图像时,我们将获得uri as

content://com.android.providers.media.documents/document/image%3A52530
Run Code Online (Sandbox Code Playgroud)

如果用户从滑动抽屉而不是最近选择画廊,那么我们将获得uri as

content://media/external/images/media/52530
Run Code Online (Sandbox Code Playgroud)

所以我已经处理好了 getRealPathFromURI_API19()

public static String getRealPathFromURI_API19(Context context, Uri uri) {
        String filePath = "";
        if (uri.getHost().contains("com.android.providers.media")) {
            // Image pick from recent 
            String wholeID = DocumentsContract.getDocumentId(uri);

            // Split at colon, use second item in the array
            String id = wholeID.split(":")[1];

            String[] column = {MediaStore.Images.Media.DATA};

            // where id is equal to
            String sel = MediaStore.Images.Media._ID + "=?";

            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{id}, null);

            int columnIndex = cursor.getColumnIndex(column[0]);

            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            cursor.close();
            return filePath;
        } else {
            // image pick from gallery 
           return  getRealPathFromURI_BelowAPI11(context,uri)
        }

    }
Run Code Online (Sandbox Code Playgroud)

编辑:如果你想在更高版本的外部SD卡中获取文件的图像路径,然后检查我的问题


Com*_*are 11

没有真正的道路.

Uri带有content方案的A 是某些内容的不透明句柄.如果它Uri代表可打开的内容,您可以使用ContentResolveropenInputStream()获取InputStream该内容.类似地,Uri带有httphttps方案的a不代表本地文件,您需要使用HTTP客户端API来访问它.

只有Uri带有file方案的a 才能标识文件(禁止在Uri创建文件后移动或删除文件的情况).

人们做的愚蠢的事情是尝试通过尝试解码文件系统路径来获取文件系统路径Uri,可能还需要调用法术来调用$EVIL_DEITY.充其量,这将是不可靠的,原因有三:

  1. 解码Uri值的规则可能会随着时间而改变,例如Android版本,因为结构Uri代表实现细节,而不是接口

  2. 即使您获得文件系统路径,您也可能无权访问该文件

  3. 并非所有Uri值都可以通过固定算法进行解码,因为许多应用程序都有自己的提供程序,这些可以指向从资产到BLOB列到需要从Internet流式传输的数据的所有内容

如果您有一些需要文件的有限API,请使用InputStreamfrom openInputStream()来制作该内容的副本.这是一个临时副本(例如,用于文件上载操作,然后删除)还是持久副本(例如,用于应用程序的"导入"功能)取决于您.


Jav*_*tar 10

编辑: 在此处使用此解决方案:https : //stackoverflow.com/a/20559175/2033223 完美运行!

首先,感谢您的解决方案@luizfelipetx

我稍微改变了你的解决方案。这对我有用:

public static String getRealPathFromDocumentUri(Context context, Uri uri){
    String filePath = "";

    Pattern p = Pattern.compile("(\\d+)$");
    Matcher m = p.matcher(uri.toString());
    if (!m.find()) {
        Log.e(ImageConverter.class.getSimpleName(), "ID for requested image not found: " + uri.toString());
        return filePath;
    }
    String imgId = m.group();

    String[] column = { MediaStore.Images.Media.DATA };
    String sel = MediaStore.Images.Media._ID + "=?";

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            column, sel, new String[]{ imgId }, null);

    int columnIndex = cursor.getColumnIndex(column[0]);

    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }
    cursor.close();

    return filePath;
}
Run Code Online (Sandbox Code Playgroud)

注意:所以我们得到了文档和图像,这取决于图像是否来自“最近”、“画廊”或其他任何内容。所以我在查找之前先提取图像ID。


Att*_*lah 9

一种简单且最好的方法将文件复制到真实路径,然后获取它们的路径,我在Android API-16 到 API-30上检查了 10 台设备,工作正常。

@Nullable
public static String createCopyAndReturnRealPath(
       @NonNull Context context, @NonNull Uri uri) {
    final ContentResolver contentResolver = context.getContentResolver();
    if (contentResolver == null)
        return null;

    // Create file path inside app's data dir
    String filePath = context.getApplicationInfo().dataDir + File.separator + "temp_file";
    File file = new File(filePath);
    try {
        InputStream inputStream = contentResolver.openInputStream(uri);
        if (inputStream == null)
            return null;
        OutputStream outputStream = new FileOutputStream(file);
        byte[] buf = new byte[1024];
        int len;
        while ((len = inputStream.read(buf)) > 0)
            outputStream.write(buf, 0, len);
        outputStream.close();
        inputStream.close();
    } catch (IOException ignore) {
        return null;
    }
    return file.getAbsolutePath();
}
Run Code Online (Sandbox Code Playgroud)