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

Posted

技术标签:

【中文标题】android 通过 Uri.getPath() 获取真实路径【英文标题】:android get real path by Uri.getPath() 【发布时间】:2011-02-16 20:55:15 【问题描述】:

我正在尝试从图库中获取图片。

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

从这个活动返回后,我有一个数据,其中包含 Uri。它看起来像:

content://media/external/images/1

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

谢谢

【问题讨论】:

这显然是一个很晚的评论,但我只想指出 startActivityForResultCode 方法将请求代码作为参数,而不是结果代码。 uri.getPath() 没有给你真正的路径吗? #Try This 尽管如此,如果您遇到问题以获取真正的路径,您可以尝试我的答案。以上答案对我没有帮助。 说明:-该方法获取URI,然后根据API级别检查您的android设备的API级别,它将生成真实路径。 生成真实路径的代码根据API级别不同。 Here is my Answer 【参考方案1】:

这就是我的工作:

Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));

和:

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;

注意:managedQuery() 方法已弃用,所以我没有使用它。

上次编辑:改进。我们应该关闭光标!!

【讨论】:

嗨@m3n0R,在 Moto G 中,MediaStore.Images.ImageColumns.DATA 列根本不存在。没有此列如何获取图像? 错误确保游标在访问数据之前已正确初始化.. 签入 API 19 无法从 CursorWindow 读取第 0 行,第 -1 列。确保在从光标访问数据之前正确初始化光标。 崩溃:java.lang.IllegalStateException:无法从 CursorWindow 读取第 0 行,列 -1。确保在从光标访问数据之前正确初始化光标。 MediaStore.Images.ImageColumns.DATA 已弃用【参考方案2】:

你真的有必要获得物理路径吗? 例如,ImageView.setImageURI()ContentResolver.openInputStream() 允许您在不知道文件真实路径的情况下访问文件的内容。

【讨论】:

这正是我一直在寻找的,但找不到。谢谢。 对不起,如果我想将此图像转换为文件,而没有获得真实路径怎么办? 物理路径可以访问文件名和扩展名。在文件上传的情况下。 如何存入数据库?【参考方案3】:

@Rene Juuse - 以上在 cmets...感谢此链接!

。 获取真实路径的代码从一个 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);

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


2016 年 3 月更新

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

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

【讨论】:

@Clocker 在三星 S4 上也没有 我真的很难在android中管理所有类型的源图像。如果您上传或从图库中选择,最好的解决方案是从 facebook 创建为图库。它是一个自定义画廊,只有设备中的真实图像,没有虚拟或临时的。我使用这个库修复了我的应用程序中的所有问题。 github.com/nohana/Laevatein 非常好的图书馆。自定义并不简单,但您可以打开代码并进行更改。我希望这可以帮助你。 在我的三星 S2 上用 4.4.1 坏了 我需要获取pdf或doc之类的文件,我无法获取路径。你能帮帮我吗? 太棒了!最后是真正有效的东西。找这个找了很久。谢谢。【参考方案4】:

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

content://com.android.providers.media.documents/document/image%3A52530

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

content://media/external/images/media/52530

所以我已经在 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)
    

EDIT1 :如果您尝试在更高版本的外部 sdcard 中获取文件的图像路径,请检查my question

EDIT2 Here 是处理虚拟文件和主机而不是com.android.providers 的完整代码我已经用content://com.adobe.scan.android.documents/document/ 测试了这个方法

【讨论】:

嗨,朋友,是的,没错。但这正在发生,因为现在谷歌有一个默认格式,可以将所有照片从您的手机上传到谷歌文档。只需将缩略图保存在手机中即可。如果您从 google docs 获得此 uri,则需要在使用之前下载照片。这一般都不好。所以,为了解决这里的所有问题,现在我正在使用这个库。 (此库仅使用本地文件,通过此解决方案您的问题将得到解决),或者您可以从库中提取代码并改进自己以解决您的问题。 github.com/nohana/Laevatein希望对你有帮助。 1+,它的工作非常适合我。正如@JaiprakasSoni 在他的回答中所说,当我在 Moto G4 游戏中运行我的应用程序时,我遇到了同样的问题,但是当我使用上面的代码时,它对我来说很好。谢谢。你节省了我的时间【参考方案5】:

编辑: 在此处使用此解决方案:https://***.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;

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

【讨论】:

【参考方案6】:

一种简单且最佳的方法将文件复制到真实路径,然后获取它们的路径我检查了 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();

【讨论】:

只是最好的 Uri-to-path 。对于大文件可能会很麻烦,但对于小文件来说效果很好。 轻松找到最好的解决方案。非常适合我需要获取小文件路径的用例。不需要文件选择库或其他复杂的解决方案来获取真实路径。最好的部分是,它适用于我所有的设备。感谢分享 由于某种原因,当我使用它时,该文件未在应用程序文件夹中创建,然后我得到它不存在 @YakirMalka 使用 temp_file 的名称创建,但没有 jpg、png ....等扩展名 是的,昨天想通了 :) 谢谢!【参考方案7】:

您好,这是我从相机或画廊拍摄图像的完整代码

//我的变量声明

protected static final int CAMERA_REQUEST = 0;
    protected static final int GALLERY_REQUEST = 1;
    Bitmap bitmap;
    Uri uri;
    Intent picIntent = null;

//点击

if (v.getId()==R.id.image_id)
            startDilog();
        

//方法体

private void startDilog() 
    AlertDialog.Builder myAlertDilog = new AlertDialog.Builder(yourActivity.this);
    myAlertDilog.setTitle("Upload picture option..");
    myAlertDilog.setMessage("Where to upload picture????");
    myAlertDilog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() 
        @Override
        public void onClick(DialogInterface dialog, int which) 
            picIntent = new Intent(Intent.ACTION_GET_CONTENT,null);
            picIntent.setType("image/*");
            picIntent.putExtra("return_data",true);
            startActivityForResult(picIntent,GALLERY_REQUEST);
        
    );
    myAlertDilog.setNegativeButton("Camera", new DialogInterface.OnClickListener() 
        @Override
        public void onClick(DialogInterface dialog, int which) 
            picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(picIntent,CAMERA_REQUEST);
        
    );
    myAlertDilog.show();

//还有其他的事情

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode==GALLERY_REQUEST)
        if (resultCode==RESULT_OK)
            if (data!=null) 
                uri = data.getData();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                try 
                    BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    options.inSampleSize = calculateInSampleSize(options, 100, 100);
                    options.inJustDecodeBounds = false;
                    Bitmap image = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    imageofpic.setImageBitmap(image);
                 catch (FileNotFoundException e) 
                    e.printStackTrace();
                
            else 
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            
        else if (resultCode == RESULT_CANCELED) 
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        
    else if (requestCode == CAMERA_REQUEST) 
        if (resultCode == RESULT_OK) 
            if (data.hasExtra("data")) 
                bitmap = (Bitmap) data.getExtras().get("data");
                uri = getImageUri(YourActivity.this,bitmap);
                File finalFile = new File(getRealPathFromUri(uri));
                imageofpic.setImageBitmap(bitmap);
             else if (data.getExtras() == null) 

                Toast.makeText(getApplicationContext(),
                        "No extras to retrieve!", Toast.LENGTH_SHORT)
                        .show();

                BitmapDrawable thumbnail = new BitmapDrawable(
                        getResources(), data.getData().getPath());
                pet_pic.setImageDrawable(thumbnail);

            

         else if (resultCode == RESULT_CANCELED) 
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        
    


private String getRealPathFromUri(Uri tempUri) 
    Cursor cursor = null;
    try 
        String[] proj =  MediaStore.Images.Media.DATA ;
        cursor = this.getContentResolver().query(tempUri,  proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
     finally 
        if (cursor != null) 
            cursor.close();
        
    

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) 
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) 

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) 
            inSampleSize *= 2;
        
    
    return inSampleSize;


private Uri getImageUri(YourActivity youractivity, Bitmap bitmap) 
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    String path = MediaStore.Images.Media.insertImage(youractivity.getContentResolver(), bitmap, "Title", null);
    return Uri.parse(path);

【讨论】:

你怎么知道这一行是100 options.inSampleSize = calculateInSampleSize(options, 100, 100);【参考方案8】:

这帮助我从图库中获取 uri 并转换为文件以进行分段上传

File file = FileUtils.getFile(this, fileUri);

https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java

【讨论】:

以上是关于android 通过 Uri.getPath() 获取真实路径的主要内容,如果未能解决你的问题,请参考以下文章

第十五周总结

播放默认铃声

安卓上的 OpenCV,Mat.rows() = 0

如何通过android上的ADB命令通过pc拨打电话?

Android环境搭建与通过命令行方式创建Android应用

Android开发之通过反射获取到Android隐藏的方法