Pobierz zawartość URI ze ścieżki pliku w Androidzie


271

Znam bezwzględną ścieżkę obrazu (np. /Sdcard/cats.jpg). Czy jest jakiś sposób, aby uzyskać identyfikator treści dla tego pliku?

Właściwie w kodzie pobieram obraz i zapisuję go w określonej lokalizacji. Aby ustawić obraz w instancji ImageView, obecnie otwieram plik za pomocą ścieżki, pobieram bajty i tworzę mapę bitową, a następnie ustawiam bitmapę w instancji ImageView. Jest to bardzo powolny proces, zamiast tego, gdybym mógł pobrać treść uri, bardzo łatwo mógłbym użyć tej metody imageView.setImageUri(uri)


23
Uri uri = Uri.parse ("file: ///sdcard/img.png");
Anand Tiwari,

13
+1 do komentarza, wystarczy Uri.parse ("file: //" + filePath) powinien załatwić sprawę
niemiecki Latorre

Uri.Parse jest amortyzowany i „do dodania”
pollaris,

@pollaris Uri.parse został dodany w API 1 i nie jest oznaczony jako przestarzały.
JP de la Torre,

Uri.parse („coś”); nie działa na mnie, nie mogę znaleźć powodu, dla którego ...
Bay

Odpowiedzi:


480

Spróbuj z:

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

Lub z:

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

3
dzięki! druga metoda działa dobrze na 1.6, 2.1 i 2.2, ale pierwsza tylko na 2.2
miszkin

28
żadna z tych metod nie rozwiązuje ścieżki pliku do identyfikatora URI treści. Rozumiem, że to rozwiązało bezpośredni problem.
Jeffrey Blattman

38
Nie koduj na stałe „/ sdcard /”; zamiast tego użyj Environment.getExternalStorageDirectory (). getPath ()
ekatz

8
Oto, co zwracają oba powyższe rozwiązania: 1. plik: ///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 Ale czego szukałem bo to coś innego. Potrzebuję URI formatu content: //. Odpowiedź Jinal wydaje się działać idealnie
Ajith Memana

5
hej Uri.fromFilenie będzie działać na
Androidzie

85

AKTUALIZACJA

Zakłada się tutaj, że Twoje media (obraz / wideo) zostały już dodane do dostawcy multimediów. Jeśli nie, nie będziesz w stanie uzyskać adresu URL zawartości dokładnie tak, jak chcesz. Zamiast tego będzie plik Uri.

Mam to samo pytanie dotyczące mojej aktywności eksploratora plików. Powinieneś wiedzieć, że contenturi pliku obsługuje tylko dane mediastore, takie jak obraz, audio i wideo. Daję ci kod do pobierania treści obrazu z wyboru obrazu z sdcard. Wypróbuj ten kod, może Ci się uda ...

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

Szukałem metody znalezienia zawartości: // URI mojego nagranego pliku wideo, a powyższy kod wydaje się działać idealnie na Nexusie 4 (Android 4.3). Byłoby miło, gdybyś mógł wyjaśnić kod.
Ajith Memana

Próbowałem tego, aby uzyskać identyfikator treści dla pliku ze ścieżką bezwzględną „/ sdcard / Image Depo / picture.png”. Nie działało, więc zdebugowałem ścieżkę kodu i stwierdziłem, że Kursor jest pusty, a gdy wpis jest dodawany do ContentProvider, jego wartość jest pusta jako Content Uri. Proszę pomóż.
Sri Krishna

1
Mam ścieżkę do pliku - plik: ///storage/emulated/0/Android/data/com.packagename/files/out.mp4, ale otrzymuję wartość null, gdy próbuję uzyskać contentUri. Próbowałem też zmienia MediaStore.Images.Mediasię MediaStore.Video.Media, ale nadal nie ma szczęścia.
Narendra Singh

1
To nie działa na Androida Pie api 28. Kursor zwraca wartość null
Ibrahim Gharyali

1
Czy możesz zaktualizować tę metodę dla Androida 10, ponieważ kolumna DANE nie jest dostępna w systemie Android 10?
Chuszbu Szah

16

// Ten kod działa dla obrazów w wersji 2.2, nie jestem pewien, czy są jakieś inne typy multimediów

   //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
świetnie, pomogło mi w udostępnianiu do Google+, ponieważ ta aplikacja wymaga strumienia multimediów z treścią Uri - ścieżka bezwzględna nie działa.
Ridcully,

1
Doskonały! Mogę potwierdzić, że działa to również z mediami typu Audio.
Matt M

16

Przyjęte rozwiązanie jest prawdopodobnie najlepszym wyborem dla twoich celów, ale aby odpowiedzieć na pytanie w temacie:

W mojej aplikacji muszę uzyskać ścieżkę z identyfikatorów URI i uzyskać identyfikator URI ze ścieżek. Były:

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

Ten ostatni (który robię w przypadku filmów, ale można go również użyć do audio lub plików lub innych rodzajów przechowywanych treści, zastępując MediaStore.Audio (itp.) Zamiast 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;
}

Zasadniczo DATAkolumna MediaStore(lub którejkolwiek podsekcji, o którą pytasz) przechowuje ścieżkę pliku, więc używasz tych informacji, aby ją wyszukać.


Nie zawsze tak jest, zwracane są dwie półgwarantowane kolumny, to znaczy, OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEjeśli aplikacja wysyłająca nawet przestrzega „reguł”. Odkryłem, że niektóre duże aplikacje zwracają tylko te dwa pola, a nie zawsze _datapole. W przypadku, gdy nie masz pola danych, które zwykle zawiera bezpośrednią ścieżkę do treści, musisz najpierw odczytać zawartość i zapisać ją w pliku lub w pamięci, a następnie masz własną ścieżkę.
Pierre

7

Możesz użyć tych dwóch sposobów w zależności od użycia

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

lub

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

Próbowałem obu sposobów i oba działają.


5

Najłatwiejszym i najskuteczniejszym sposobem tworzenia treści Uri content://z pliku jest użycie FileProvider . Uri dostarczone przez FileProvider może być również używane do udostępniania plików innym aplikacjom. Aby pobrać Uri pliku z bezwzględnej ścieżki File, możesz użyć DocumentFile.fromFile (nowy plik (ścieżka, nazwa)), został dodany w Api 22 i zwraca null dla wersji poniżej.

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


2

Uzyskiwanie identyfikatora pliku bez pisania kodu, tylko za pomocą poleceń CLI powłoki 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 dostaje prawdziwą ścieżkę z treści uri”, a to pytanie jest na pierwszym miejscu, a treść odpowiedzi na 0 głosów w podsumowaniu wyników wyszukiwania. Pozwól mi więc głosować jako pierwszy. Dzięki, stary!
Weekend

To jest fajne. Ale wydaje się Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY, że dostaniesz:, chyba że jesteś zrootowany.
not2qubit

więc to wymaga dostępu roota do telefonu?
Samintha Kaveesh

1

Lepiej jest użyć sprawdzania poprawności do obsługi wersji wcześniejszych niż Android N, na przykład:

  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

Możesz wypróbować poniższy fragment kodu

    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
Co to jest VOLUME_NAME?
Evgenii Vorobei

Jest „zewnętrzny” lub „wewnętrzny”
caopeng,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.