【问题标题】:Get content uri from file path in android从android中的文件路径获取内容uri
【发布时间】:2011-03-01 14:07:24
【问题描述】:

我知道图像的绝对路径(例如 /sdcard/cats.jpg)。有什么方法可以获取该文件的内容 uri 吗?

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

【问题讨论】:

  • Uri uri = Uri.parse("file:///sdcard/img.png");
  • +1 评论,只需 Uri.parse("file://" + filePath) 就可以了
  • Uri.Parse 已弃用且“待添加”
  • @pollaris Uri.parse 已添加到 API 1 中,并且未标记为弃用。
  • Uri.parse("something");对我不起作用,我找不到原因...

标签: android image


【解决方案1】:

从文件中创建内容 Uri content:// 的最简单且可靠的方法是使用 FileProvider。 FileProvider 提供的 Uri 也可用于与其他应用程序共享文件的 Uri。要从File 的绝对路径获取文件 Uri,您可以使用 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 = FileProvider.getUriForFile(getContext(), "com.mydomain.fileprovider", newFile);

【讨论】:

    【解决方案2】:

    更新

    这里假设您的媒体(图像/视频)已添加到内容媒体提供商。如果没有,那么您将无法获得 内容 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;
        }
      }
    }
    

    为了支持android Q

    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()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                ContentResolver resolver = context.getContentResolver();
                Uri picCollection = MediaStore.Images.Media
                        .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
                ContentValues picDetail = new ContentValues();
                picDetail.put(MediaStore.Images.Media.DISPLAY_NAME, imageFile.getName());
                picDetail.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
                picDetail.put(MediaStore.Images.Media.RELATIVE_PATH,"DCIM/" + UUID.randomUUID().toString());
                picDetail.put(MediaStore.Images.Media.IS_PENDING,1);
                Uri finaluri = resolver.insert(picCollection, picDetail);
                picDetail.clear();
                picDetail.put(MediaStore.Images.Media.IS_PENDING, 0);
                resolver.update(picCollection, picDetail, null, null);
                return finaluri;
            }else {
                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) 上完美运行。如果您能解释一下代码,那就太好了。
    • 我已经尝试过使用绝对路径“/sdcard/Image Depo/picture.png”获取文件的内容 Uri。它不起作用,所以我调试了代码路径,发现 Cursor 是空的,并且当将条目添加到 ContentProvider 时,它会将 null 作为 Content Uri。请帮忙。
    • 我有文件路径 - file:///storage/emulated/0/Android/data/com.packagename/files/out.mp4,但是当我尝试获取 contentUri 时得到空值。我也尝试将MediaStore.Images.Media 更改为MediaStore.Video.Media,但仍然没有运气。
    • 这不适用于 android Pie api 28。光标返回 null
    • 您能否为 Android 10 更新此方法,因为在 Android 10 中无法访问 DATA 列?
    【解决方案3】:

    最好使用验证来支持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

    【讨论】:

      【解决方案4】:

      它已经晚了,但将来可能会对某人有所帮助。

      要获取文件的内容 URI,您可以使用以下方法:

      FileProvider.getUriForFile(Context context, String authority, File file)

      它返回内容 URI。

      Check this out to learn how to setup a FileProvider

      【讨论】:

        【解决方案5】:

        你可以试试下面的代码sn -p

            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;
        }
        

        【讨论】:

        • 什么是 VOLUME_NAME?
        • 是“外部”还是“内部”
        【解决方案6】:

        你可以根据用途来使用这两种方式

        Uri uri = Uri.parse("String file location");

        Uri uri = Uri.fromFile(new File("string file location"));

        两种方法我都试过了。

        【讨论】:

          【解决方案7】:

          尝试:

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

          或与:

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

          【讨论】:

          • 谢谢!第二种方法适用于 1.6、2.1 和 2.2,但第一种方法仅适用于 2.2
          • 这些方法都不能将文件路径解析为内容 URI。我知道它解决了眼前的问题。
          • 不要硬编码“/sdcard/”;改用 Environment.getExternalStorageDirectory().getPath()
          • 这是上述两种解决方案返回的结果: 1. file:///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/ VID_20140312_171146.mp4 但我一直在寻找不同的东西。我需要 content:// 格式的 URI。 Jinal 的回答似乎很完美
          • Uri.fromFile 无法在 android 26+ 上运行,您应该使用文件提供程序
          【解决方案8】:

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

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

          【讨论】:

          • Google "adb get real path from content uri" 这个问题排在前 1,你的 0 票答案的内容在搜索结果摘要中。所以让我成为第一个投票的人。谢谢兄弟!
          • 这很酷。但似乎你会得到:Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,除非你是 root。
          • 所以这需要手机的root权限吗?
          【解决方案9】:

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

          在我的应用程序中,我必须从 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;
          }
          

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

          【讨论】:

          • 并非总是如此,返回两个半保证列,即OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZE,如果发送应用程序甚至遵循“规则”。我发现一些主要的应用程序只返回这两个字段,并不总是返回 _data 字段。如果您没有通常包含内容直接路径的数据字段,则必须首先读取内容并将其写入文件或内存中,然后您才能拥有自己的路径。
          【解决方案10】:

          //此代码适用于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();
              }
             };
          

          【讨论】:

          • 太棒了,帮助我分享到 Google+,因为该应用需要带有内容 Uri 的媒体流——绝对路径不起作用。
          • 太棒了!我可以确认这也适用于音频媒体类型。
          猜你喜欢
          • 1970-01-01
          • 2020-06-10
          • 2014-07-31
          • 1970-01-01
          • 2019-08-17
          • 1970-01-01
          • 2023-03-09
          • 1970-01-01
          • 2012-08-15
          相关资源
          最近更新 更多