从Android中的文件路径获取内容uri


271

我知道图像的绝对路径(例如/sdcard/cats.jpg)。有没有办法获取此文件的内容uri?

实际上,在我的代码中,我下载了一个图像并将其保存在特定位置。为了在ImageView实例中设置图像,当前我使用路径打开文件,获取字节并创建位图,然后在ImageView实例中设置位图。这是一个非常缓慢的过程,相反,如果我可以获得内容uri,那么我可以非常轻松地使用该方法 imageView.setImageUri(uri)


23
Uri uri = Uri.parse(“ file:///sdcard/img.png”);
阿南德·蒂瓦里

13
+1到评论,只是Uri.parse(“ file://” + filePath)应该可以解决问题
德国拉托尔2014年

Uri.Parse已贬值并“要添加”
pollaris

@pollaris Uri.parse已添加到API 1中,并且未标记为弃用。
JP de la Torre

Uri.parse(“ something”); 不在我身上工作,我找不到原因...
海湾

Answers:


480

尝试:

ImageView.setImageURI(Uri.fromFile(new File("/sdcard/cats.jpg")));

或搭配:

ImageView.setImageURI(Uri.parse(new File("/sdcard/cats.jpg").toString()));

3
谢谢!第二种方法适用于
1.6、2.1

28
这些方法都无法解析内容URI的文件路径。我知道它解决了眼前的问题。
Jeffrey Blattman 2011年

38
不要硬编码“ / sdcard /”;使用Environment.getExternalStorageDirectory()。getPath()代替
ekatz 2012年

8
这是上述两种解决方案返回的结果:1. file:///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4但是我在看什么因为是不同的。我需要content://格式URI。从Jinal答案似乎工作完美
阿吉特Memana

5
Uri.fromFile在Android 26+上无法正常使用,您应该使用文件提供程序
vuhung3990 '18

85

更新

此处假定您的媒体(图像/视频)已添加到内容媒体提供者。否则,您将无法获得所需的内容URL。而是会有文件Uri。

我对文件浏览器活动有相同的问题。您应该知道,文件的contenturi仅支持媒体存储数据,例如图像,音频和视频。我给你的代码,用于从sdcard中选择图像来获取图像内容uri。试试这个代码,也许它将为您服务...

public static Uri getImageContentUri(Context context, File imageFile) {
  String filePath = imageFile.getAbsolutePath();
  Cursor cursor = context.getContentResolver().query(
      MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
      new String[] { MediaStore.Images.Media._ID },
      MediaStore.Images.Media.DATA + "=? ",
      new String[] { filePath }, null);
  if (cursor != null && cursor.moveToFirst()) {
    int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
    cursor.close();
    return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + id);
  } else {
    if (imageFile.exists()) {
      ContentValues values = new ContentValues();
      values.put(MediaStore.Images.Media.DATA, filePath);
      return context.getContentResolver().insert(
          MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    } else {
      return null;
    }
  }
}

我一直在寻找一种方法来找到我录制的视频文件的content:// URI,而以上代码似乎在Nexus 4(Android 4.3)上可以正常使用。如果您能解释一下代码,那就太好了。
Ajith Memana 2014年

我已经尝试过用绝对路径“ / sdcard / Image Depo / picture.png”获取文件的内容Uri。它没有用,所以我调试了代码路径,发现Cursor为空,并且在将条目添加到ContentProvider时,其值为null作为Content Uri。请帮忙。
克里希纳

1
我有文件路径-file:///storage/emulated/0/Android/data/com.packagename/files/out.mp4,但是当我尝试获取contentUri时却为null。我也尝试更改MediaStore.Images.MediaMediaStore.Video.Media,但仍然没有运气。
Narendra Singh

1
这不适用于android Pie
api28。

1
您是否可以为Android 10更新此方法,因为Android 10中无法访问DATA列?
库舒卜沙

16

//此代码适用于2.2上的图像,不确定是否还有其他媒体类型

   //Your file path - Example here is "/sdcard/cats.jpg"
   final String filePathThis = imagePaths.get(position).toString();

   MediaScannerConnectionClient mediaScannerClient = new
   MediaScannerConnectionClient() {
    private MediaScannerConnection msc = null;
    {
        msc = new MediaScannerConnection(getApplicationContext(), this);
        msc.connect();
    }

    public void onMediaScannerConnected(){
        msc.scanFile(filePathThis, null);
    }


    public void onScanCompleted(String path, Uri uri) {
        //This is where you get your content uri
            Log.d(TAG, uri.toString());
        msc.disconnect();
    }
   };

1
太好了,对我分享到Google+有所帮助,因为该应用需要包含内容Uri的媒体流-绝对路径无效。
Ridcully 2012年

1
优秀的!我可以确认这也适用于音频媒体类型。
Matt M

16

接受的解决方案可能是您最佳的选择,但实际上可以在主题行中回答问题:

在我的应用程序中,我必须从URI获取路径,并从路径获取URI。前者:

/**
 * Gets the corresponding path to a file from the given content:// URI
 * @param selectedVideoUri The content:// URI to find the file path from
 * @param contentResolver The content resolver to use to perform the query.
 * @return the file path as a string
 */
private String getFilePathFromContentUri(Uri selectedVideoUri,
        ContentResolver contentResolver) {
    String filePath;
    String[] filePathColumn = {MediaColumns.DATA};

    Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    filePath = cursor.getString(columnIndex);
    cursor.close();
    return filePath;
}

后者(我用于视频,但也可以通过用MediaStore.Audio(等)替换MediaStore.Video来用于音频或文件或其他类型的存储内容):

/**
 * Gets the MediaStore video ID of a given file on external storage
 * @param filePath The path (on external storage) of the file to resolve the ID of
 * @param contentResolver The content resolver to use to perform the query.
 * @return the video ID as a long
 */
private long getVideoIdFromFilePath(String filePath,
        ContentResolver contentResolver) {


    long videoId;
    Log.d(TAG,"Loading file " + filePath);

            // This returns us content://media/external/videos/media (or something like that)
            // I pass in "external" because that's the MediaStore's name for the external
            // storage on my device (the other possibility is "internal")
    Uri videosUri = MediaStore.Video.Media.getContentUri("external");

    Log.d(TAG,"videosUri = " + videosUri.toString());

    String[] projection = {MediaStore.Video.VideoColumns._ID};

    // TODO This will break if we have no matching item in the MediaStore.
    Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] { filePath }, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(projection[0]);
    videoId = cursor.getLong(columnIndex);

    Log.d(TAG,"Video ID is " + videoId);
    cursor.close();
    return videoId;
}

基本上,该DATAMediaStore(或您要查询的任何子节)存储文件路径,因此您可以使用该信息进行查找。


并非总是这样,有两个返回的半保证列,也就是说OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZE,发送方的应用程序甚至遵循“规则”。我发现一些主要的应用程序仅返回这两个字段,而并不总是返回该_data字段。如果没有通常包含指向内容的直接路径的数据字段,则必须先读取内容并将其写入文件或内存,然后才拥有自己的路径。
Pierre


5

content://从文件创建内容Uri的最简单,最可靠的方法是使用FileProvider。FileProvider提供的Uri也可以用于提供Uri以便与其他应用程序共享文件。要从绝对路径获取File Uri,File可以使用DocumentFile.fromFile(new File(path,name)),它已添加到Api 22中,并且对于以下版本返回null。

File imagePath = new File(Context.getFilesDir(), "images");
File newFile = new File(imagePath, "default_image.jpg");
Uri contentUri = getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);


2

仅使用adb shell CLI命令即可获取文件ID,而无需编写任何代码:

adb shell content query --uri "content://media/external/video/media" | grep FILE_NAME | grep -Eo " _id=([0-9]+)," | grep -Eo "[0-9]+"

Google“ adb从内容uri获取真实路径”,该问题排在第一位,搜索结果摘要中包含0票答案的内容。因此,让我成为第一个投票的人。谢啦兄弟!
周末

这很酷。但似乎您会得到:Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,除非您扎根。
not2qubit

所以这需要手机的root访问吗?
Samintha Kaveesh

1

最好使用验证来支持Android N之前的版本,例如:

  if (Build.VERSION.SDK_INT >=  Build.VERSION_CODES.N) {
     imageUri = Uri.parse(filepath);
  } else{
     imageUri = Uri.fromFile(new File(filepath));
  }

  if (Build.VERSION.SDK_INT >=  Build.VERSION_CODES.N) {
     ImageView.setImageURI(Uri.parse(new File("/sdcard/cats.jpg").toString()));         
  } else{
     ImageView.setImageURI(Uri.fromFile(new File("/sdcard/cats.jpg")));
  }

https://es.stackoverflow.com/questions/71443/reporte-crash-android-os-fileuriexposedexception-en-android-n


0

你可以尝试下面的代码片段

    public Uri getUri(ContentResolver cr, String path){
    Uri mediaUri = MediaStore.Files.getContentUri(VOLUME_NAME);
    Cursor ca = cr.query(mediaUri, new String[] { MediaStore.MediaColumns._ID }, MediaStore.MediaColumns.DATA + "=?", new String[] {path}, null);
    if (ca != null && ca.moveToFirst()) {
        int id = ca.getInt(ca.getColumnIndex(MediaStore.MediaColumns._ID));
        ca.close();
        return  MediaStore.Files.getContentUri(VOLUME_NAME,id);
    }
    if(ca != null) {
        ca.close();
    }
    return null;
}

1
什么是VOLUME_NAME?
Evgenii Vorobei

它是“外部”还是“内部”
caopeng
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.