Ottieni contenuti uri dal percorso del file in Android


271

Conosco il percorso assoluto di un'immagine (ad esempio, /sdcard/cats.jpg). C'è un modo per ottenere l'uri di contenuto per questo file?

In realtà nel mio codice, scarico un'immagine e la salvo in una posizione particolare. Per impostare l'immagine in un'istanza di ImageView, attualmente apro il file usando il percorso, ottengo i byte e creo una bitmap e quindi imposto la bitmap nell'istanza di ImageView. Questo è un processo molto lento, invece se potessi ottenere il contenuto uri allora potrei usare molto facilmente il metodo imageView.setImageUri(uri)


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

13
+1 al commento, solo Uri.parse ("file: //" + filePath) dovrebbe fare il trucco
German Latorre

Uri.Parse è ammortizzato e "da aggiungere"
pollaris,

@pollaris Uri.parse è stato aggiunto nell'API 1 e non è contrassegnato per l'ammortamento.
JP de la Torre,

Uri.parse ( "qualcosa"); non funziona su di me, non riesco a trovare il motivo per cui ...
Bay

Risposte:


480

Prova con:

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

O con:

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

3
Grazie! il secondo metodo funziona bene su 1.6, 2.1 e 2.2 ma il primo solo su 2.2
mishkin il

28
nessuno di questi metodi risolve un percorso di file in un URI del contenuto. capisco che ha risolto il problema immediato però.
Jeffrey Blattman,

38
Non codificare "/ sdcard /"; usa Environment.getExternalStorageDirectory (). getPath () invece
ekatz

8
Ecco cosa restituiscono entrambe le soluzioni precedenti: 1. file: ///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 Ma quello che stavo cercando perché è qualcosa di diverso. Ho bisogno del contenuto: // format URI. La risposta di Jinal sembra funzionare perfettamente
Ajith Memana,

5
hey Uri.fromFilenon funzionerà su Android 26+, dovresti usare il file provider
vuhung3990

85

AGGIORNARE

Qui si presume che il tuo media (Immagine / Video) sia già stato aggiunto al provider di contenuti multimediali. In caso contrario, non sarai in grado di ottenere l'URL del contenuto esattamente come desideri. Invece ci sarà il file Uri.

Ho avuto la stessa domanda per la mia attività di esplorazione di file. Dovresti sapere che il contenturi per file supporta solo dati di mediastore come immagini, audio e video. Ti sto dando il codice per ottenere uri dal contenuto dell'immagine selezionando un'immagine da sdcard. Prova questo codice, forse funzionerà per te ...

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

Stavo cercando un metodo per trovare il contenuto: // URI del mio file video registrato e il codice sopra sembra funzionare perfettamente su Nexus 4 (Android 4.3). Sarebbe bello se per favore puoi spiegare il codice.
Ajith Memana,

Ho provato questo per ottenere l'Uri del contenuto per un file con il percorso assoluto "/ sdcard / Image Depo / picture.png". Non ha funzionato, quindi ho eseguito il debug del percorso del codice e ho scoperto che il cursore è vuoto e quando la voce viene aggiunta a ContentProvider, viene restituito null come Uri del contenuto. Per favore aiuto.
Sri Krishna,

1
Ho il percorso del file - file: ///storage/emulated/0/Android/data/com.packagename/files/out.mp4, ma ottengo null quando provo a ottenere contentUri. Ho anche provato a cambiare MediaStore.Images.Mediaa MediaStore.Video.Media, ma ancora senza fortuna.
Narendra Singh,

1
Questo non funziona su Android Pie api 28. Il cursore restituisce null
Ibrahim Gharyali

1
Puoi aggiornare questo metodo per Android 10 in quanto la colonna DATA non è accessibile in Android 10?
Khushbu Shah,

16

// Questo codice funziona per le immagini su 2.2, non sono sicuro se ci siano altri tipi di media

   //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
fantastico, mi ha aiutato con la condivisione su Google+, poiché quell'app richiede un flusso multimediale con un contenuto Uri - il percorso assoluto non funziona.
Ridcully,

1
Eccellente! Posso confermare che funziona anche con i tipi di media Audio.
Matt M

16

La soluzione accettata è probabilmente la migliore scommessa per i tuoi scopi, ma per rispondere effettivamente alla domanda nell'oggetto:

Nella mia app, devo ottenere il percorso dagli URI e ottenere l'URI dai percorsi. L'ex:

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

Quest'ultimo (che faccio per i video, ma può essere utilizzato anche per audio o file o altri tipi di contenuti memorizzati sostituendo MediaStore.Audio (ecc.) Con 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;
}

Fondamentalmente, la DATAcolonna di MediaStore(o qualunque sottosezione di cui stai interrogando) memorizza il percorso del file, quindi usi quelle informazioni per cercarlo.


Non sempre, ci sono due colonne semi-garantite restituite, e cioè OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEse l'app di invio segue anche le "regole". Ho scoperto che alcune app principali restituiscono solo questi due campi e non sempre il _datacampo. Nel caso in cui non si disponga del campo dati che normalmente contiene un percorso diretto al contenuto, è necessario prima leggere il contenuto e scriverlo in un file o in memoria e quindi disporre del proprio percorso.
Pierre,

7

È possibile utilizzare questi due modi in base all'uso

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

o

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

Ho provato in entrambi i modi ed entrambi i lavori.


5

Il modo più semplice e affidabile per creare Uri di contenuto content://da un file è utilizzare FileProvider . Uri fornito da FileProvider può essere utilizzato anche fornendo Uri anche per la condivisione di file con altre app. Per ottenere File Uri da un percorso assoluto Fileè possibile utilizzare DocumentFile.fromFile (nuovo file (percorso, nome)), viene aggiunto in Api 22 e restituisce null per le versioni seguenti.

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


2

Ottenere l'ID file senza scrivere alcun codice, solo con i comandi CLI della shell 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 ottiene un percorso reale dai contenuti uri" e questa domanda è tra le prime 1, con i contenuti della tua risposta a 0 voti nel riepilogo dei risultati di ricerca. Vorrei essere il primo a votare. Grazie Fratello!
Weekend

Questo è fico. Ma sembra che otterrai: a Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLYmeno che tu non sia radicato.
not2qubit,

quindi questo ha bisogno dell'accesso root del telefono?
Samintha Kaveesh,

1

È meglio utilizzare una convalida per supportare le versioni precedenti ad Android N, ad esempio:

  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

Puoi provare sotto lo snippet di codice

    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
Che cos'è VOLUME_NAME?
Evgenii Vorobei,

È "esterno" o "interno"
caopeng
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.