Отримайте вміст Uri з шляху файлів на Android


271

Я знаю абсолютний шлях зображення (скажімо, наприклад, /sdcard/cats.jpg). Чи є спосіб отримати вміст урі для цього файлу?

Насправді у своєму коді я завантажую зображення та зберігаю його у певному місці. Для того, щоб встановити зображення в екземплярі ImageView, в даний час я відкриваю файл за допомогою шляху, отримую байти і створюю растрову карту, а потім встановлюю растрову карту в екземплярі ImageView. Це дуже повільний процес, натомість, якби я міг отримати вміст урі, то я міг би дуже легко використовувати метод imageView.setImageUri(uri)


23
Uri uri = Uri.parse ("файл: ///sdcard/img.png");
Ананд Тіварі

13
+1 до коментаря, просто Uri.parse ("файл: //" + filePath) повинен зробити трюк
німецький Latorre

Uri.Parse знецінюється і "додається"
pollaris

@pollaris Uri.parse додано в API 1, і він не позначений для депрекації.
JP de la Torre

Uri.parse ("щось"); не працює на мене, я не можу знайти причину, чому ...
Бей

Відповіді:


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. файл: ///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). Було б добре, якщо ви можете, будь ласка, пояснити код.
Аджит Мемана

Я спробував це зробити, щоб отримати вміст Uri для файлу з абсолютним контуром "/ sdcard / Image Depo / picture.png". Це не спрацювало, тож я зафіксував шлях коду і виявив, що Курсор порожній, а коли додавання додається до ContentProvider, його дано null як Content Uri. Будь ласка, допоможіть.
Шрі Крішна

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

1
Це не працює на android Pie api 28. Курсор повертається до нуля
Ibrahim Gharyali

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 - абсолютний шлях не працює.
Ridcully

1
Відмінно! Я можу підтвердити, що це працює і з типами аудіо медіа.
Метт М

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

Найпростіший і надійний спосіб створення вмісту Uri content://з файлу - це використання FileProvider . Uri, наданий FileProvider, також може використовуватися, надаючи Uri для обміну файлами з іншими програмами. Щоб отримати File Uri з абсолютного шляху Fileви можете використовувати DocumentFile.fromFile (новий файл (шлях, ім'я)), він доданий в 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

Отримання ідентифікатора файлу без написання коду, лише за допомогою команд CLI adb shell:

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

так що для цього потрібен кореневий доступ до телефону?
Самінта Кавееш

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.