Récupérer l'URI du contenu depuis le chemin du fichier dans Android

271

Je connais le chemin absolu d'une image (disons, par exemple, /sdcard/cats.jpg). Existe-t-il un moyen d'obtenir l'URI du contenu de ce fichier?

En fait dans mon code, je télécharge une image et l'enregistre à un endroit particulier. Afin de définir l'image dans une instance d'ImageView, actuellement j'ouvre le fichier en utilisant le chemin, récupère les octets et crée un bitmap, puis définit le bitmap dans l'instance d'ImageView. C'est un processus très lent, mais si je pouvais obtenir le contenu uri, je pourrais très facilement utiliser la méthode imageView.setImageUri(uri)

pankajagarwal
la source
23
Uri uri = Uri.parse ("fichier: ///sdcard/img.png");
Anand Tiwari
13
+1 au commentaire, juste Uri.parse ("file: //" + filePath) devrait faire l'affaire
Latorre allemand
Uri.Parse est amorti et "à ajouter"
pollaris
@pollaris Uri.parse a été ajouté dans l'API 1 et il n'est pas marqué pour dépréciation.
JP de la Torre
Uri.parse ("quelque chose"); ne travaille pas sur moi, je ne trouve pas la raison pour laquelle ...
Bay

Réponses:

480

Essayez avec:

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

Ou avec:

ImageView.setImageURI(Uri.parse(new File("/sdcard/cats.jpg").toString()));
Francesco Laurita
la source
3
Merci! la deuxième méthode fonctionne bien sur 1.6, 2.1 et 2.2 mais la première uniquement sur 2.2
mishkin
28
aucune de ces méthodes ne résout un chemin de fichier vers un URI de contenu. je comprends que cela a résolu le problème immédiat.
Jeffrey Blattman
38
Ne codez pas en dur "/ sdcard /"; utilisez plutôt Environment.getExternalStorageDirectory (). getPath ()
ekatz
8
Voici ce que les deux solutions ci-dessus renvoient: 1. file: ///storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 2. /storage/emulated/0/DCIM/Camera/VID_20140312_171146.mp4 Mais ce que je cherchais car c'est quelque chose de différent. J'ai besoin du contenu: // format URI. La réponse de Jinal semble fonctionner parfaitement
Ajith Memana
5
hey Uri.fromFilene fonctionnera pas sur android 26+, vous devez utiliser le fournisseur de fichiers
vuhung3990
85

METTRE À JOUR

Ici, il est supposé que votre média (image / vidéo) est déjà ajouté au fournisseur de contenu multimédia. Sinon, vous ne pourrez pas obtenir l'URL de contenu aussi exacte que vous le souhaitez. Au lieu de cela, il y aura le fichier Uri.

J'avais la même question pour mon activité d'exploration de fichiers. Vous devez savoir que le contenturi pour le fichier ne prend en charge que les données de médiastore comme l'image, l'audio et la vidéo. Je vous donne le code pour obtenir le contenu de l'image uri en sélectionnant une image depuis sdcard. Essayez ce code, peut-être que cela fonctionnera pour vous ...

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
la source
Je cherchais une méthode pour trouver le contenu: // URI de mon fichier vidéo enregistré et le code ci-dessus semble fonctionner parfaitement sur Nexus 4 (Android 4.3). Ce serait bien si vous pouviez expliquer le code.
Ajith Memana
J'ai essayé ceci pour obtenir l'URI de contenu pour un fichier avec le chemin absolu "/ sdcard / Image Depo / picture.png". Cela n'a pas fonctionné, j'ai donc débogué le chemin du code et constaté que le curseur est vide, et lorsque l'entrée est ajoutée à ContentProvider, son donnant null comme Content Uri. Veuillez aider.
Sri Krishna
1
J'ai le chemin du fichier - file: ///storage/emulated/0/Android/data/com.packagename/files/out.mp4, mais en obtenant null lorsque j'essaye d'obtenir contentUri. J'ai aussi essayé de changer MediaStore.Images.Mediaà MediaStore.Video.Media, mais toujours pas de chance.
Narendra Singh
1
Cela ne fonctionne pas sur l'API Android Pie 28. Le curseur renvoie null
Ibrahim Gharyali
1
Pouvez-vous mettre à jour cette méthode pour Android 10 car la colonne DATA n'est pas accessible dans Android 10?
Khushbu Shah
16

// Ce code fonctionne pour les images sur 2.2, je ne sais pas si d'autres types de médias

   //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
la source
1
génial, m'a aidé à partager sur Google+, car cette application nécessite un flux multimédia avec un Uri de contenu - le chemin absolu ne fonctionne pas.
Ridcully
1
Excellent! Je peux également confirmer que cela fonctionne avec les types de supports audio.
Matt M
16

La solution acceptée est probablement la meilleure solution pour vos besoins, mais pour répondre à la question dans la ligne d'objet:

Dans mon application, je dois obtenir le chemin des URI et obtenir l'URI des chemins. L'ancien:

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

Ce dernier (ce que je fais pour les vidéos, mais peut également être utilisé pour l'audio ou les fichiers ou d'autres types de contenu stocké en substituant MediaStore.Audio (etc.) à 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;
}

Fondamentalement, la DATAcolonne MediaStore(ou la sous-section de celle-ci que vous interrogez) stocke le chemin du fichier, vous utilisez donc ces informations pour le rechercher.

Jon O
la source
Pas toujours le cas, il y a deux colonnes semi-garanties retournées, et c'est OpenableColumns.DISPLAY_NAME & OpenableColumns.SIZEsi l'application d'envoi suit même les "règles". J'ai trouvé que certaines applications majeures ne renvoient que ces deux champs et pas toujours le _datachamp. Dans le cas où vous n'avez pas le champ de données qui contient normalement un chemin direct vers le contenu, vous devez d'abord lire le contenu et l'écrire dans un fichier ou en mémoire, puis vous avez votre propre chemin.
Pierre
7

Vous pouvez utiliser ces deux façons en fonction de l'utilisation

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

ou

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

J'ai essayé les deux façons et les deux œuvres.

Abhishek Meharia
la source
5

Le moyen le plus simple et le plus robuste pour créer content://de l' URI de contenu à partir d'un fichier est d'utiliser FileProvider . L'URI fourni par FileProvider peut également être utilisé pour fournir également l'URI pour le partage de fichiers avec d'autres applications. Pour obtenir File Uri à partir d'un chemin absolu, Filevous pouvez utiliser DocumentFile.fromFile (nouveau fichier (chemin, nom)), il est ajouté dans Api 22 et renvoie null pour les versions ci-dessous.

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

Obtention de l'ID de fichier sans écrire de code, juste avec les commandes CLI du shell adb:

adb shell content query --uri "content://media/external/video/media" | grep FILE_NAME | grep -Eo " _id=([0-9]+)," | grep -Eo "[0-9]+"
BogdanBiv
la source
Google "adb obtient un chemin réel depuis l'URI du contenu" et cette question est dans le top 1, avec le contenu de votre réponse à 0 vote dans le résumé des résultats de la recherche. Alors laissez-moi être le premier à voter. Merci mon ami!
week
C'est cool. Mais il semble que vous obtiendrez:, Permission Denial: Do not have permission in call getContentProviderExternal() from pid=15660, uid=10113 requires android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLYsauf si vous êtes enraciné.
not2qubit
donc cela nécessite un accès root au téléphone?
Samintha Kaveesh
1

Est préférable d'utiliser une validation pour prendre en charge les versions antérieures à Android N, par exemple:

  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
la source
0

Vous pouvez essayer l'extrait de code ci-dessous

    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
la source
1
Qu'est-ce que VOLUME_NAME?
Evgenii Vorobei
C'est "externe" ou "interne"
caopeng