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)

pankajagarwal
źródło
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()));
Francesco Laurita
źródło
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;
    }
  }
}
Jinal Jogiyani
źródło
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();
    }
   };
AndroidDebaser
źródło
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ć.

Jon O
źródło
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ą.

Abhishek Meharia
źródło
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);
Tracki
źródło
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]+"
BogdanBiv
źródło
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

Jorgesys
źródło
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;
}
caopeng
źródło
1
Co to jest VOLUME_NAME?
Evgenii Vorobei
Jest „zewnętrzny” lub „wewnętrzny”
caopeng,