Получить содержимое URI из пути к файлу в Android


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) должен добиться цели
немецкий Latorre

Uri.Parse обесценивается и «будет добавлен»
pollaris

@pollaris Uri.parse был добавлен в API 1 и не помечен как устаревший.
JP de la Torre

Uri.parse ( "что - то"); не работает на меня, я не могу найти причину, почему ...
Bay

Ответы:


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 и 2.2, но первый - только на 2.2
Мишкин

28
ни один из этих методов не разрешает путь файла к URI контента. Я понимаю, что это решило насущную проблему.
Джеффри Блатман

38
Не используйте жесткий код "/ sdcard /"; используйте взамен Environment.getExternalStorageDirectory (). getPath ()
ekatz

8
Это то, что оба вышеуказанных решения возвращают: 1. file: ///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 Но то, что я искал ибо это что-то другое. Мне нужен контент: // формат URI. Ответ от Джинала, кажется, работает отлично
Аджит Мемана

5
эй Uri.fromFileне будет работать на Android 26+, вы должны использовать файловый провайдер
vuhung3990

85

ОБНОВИТЬ

Здесь предполагается, что ваш медиафайл (изображение / видео) уже добавлен в контент-провайдера. Если нет, то вы не сможете получить URL-адрес содержимого точно таким, как вы хотите. Вместо этого будет файл Uri.

У меня был такой же вопрос для моей файловой активности. Вы должны знать, что contenturi для файла поддерживает только медиастроительные данные, такие как изображения, аудио и видео. Я даю вам код для получения изображения URI от выбора изображения из SDCard. Попробуйте этот код, может быть, он будет работать для вас ...

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

Я искал способ найти контент: // URI моего записанного видеофайла, и приведенный выше код, кажется, отлично работает на Nexus 4 (Android 4.3). Было бы хорошо, если бы вы могли объяснить код.
Аджит Мемана

Я пробовал это, чтобы получить Content Uri для файла с абсолютным путем "/ sdcard / Image Depo / picture.png". Это не сработало, поэтому я отладил путь к коду и обнаружил, что Курсор пуст, и когда запись добавляется в ContentProvider, она дает нулевое значение как Content Uri. Пожалуйста помоги.
Шри Кришна

1
У меня есть путь к файлу - file: ///storage/emulated/0/Android/data/com.packagename/files/out.mp4, но он становится нулевым, когда я пытаюсь получить contentUri. Я тоже пытался перейти MediaStore.Images.Mediaна MediaStore.Video.Media, но все же не повезло.
Нарендра Сингх

1
Это не работает на Android Pie Api 28. Курсор возвращает
ноль

1
Можете ли вы обновить этот метод для Android 10, так как столбец DATA недоступен в Android 10?
Хушбу Шах

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 - абсолютный путь не работает.
Чудесно

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

По сути, в DATAстолбце MediaStore(или в любом из его подразделов, к которому вы обращаетесь) хранится путь к файлу, поэтому вы используете эту информацию для его поиска.


Не всегда, возвращаются два полугарантированных столбца, и это OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEесли отправляющее приложение даже следует «правилам». Я обнаружил, что некоторые основные приложения возвращают только эти два поля, а не всегда _dataполе. В случае, когда у вас нет поля данных, которое обычно содержит прямой путь к контенту, вы должны сначала прочитать контент и записать его в файл или в память, а затем у вас есть свой собственный путь.
Пьер

7

Вы можете использовать эти два способа в зависимости от использования

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

или

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

Я пробовал оба пути, и оба работают.


5

Самый простой и надежный способ создания Content Uri content://из файла - это использование FileProvider . Uri, предоставляемый FileProvider, можно использовать также, предоставляя Uri для обмена файлами с другими приложениями. Чтобы получить File Uri по абсолютному пути, Fileвы можете использовать DocumentFile.fromFile (новый файл (путь, имя)), он добавлен в Api 22 и возвращает ноль для версий ниже.

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:

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-доступ телефона?
Саминта Кавеиш

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?
Евгений Воробей

Это «внешний» или «внутренний»
caopeng
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.