web-dev-qa-db-fra.com

android obtenir le chemin réel par Uri.getPath ()

J'essaie d'obtenir une image de la galerie. 

Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select picture"), resultCode );

Après mon retour de cette activité, j'ai des données, qui contiennent Uri. Ça ressemble à:

content://media/external/images/1

Comment puis-je convertir ce chemin en chemin réel (comme '/sdcard/image.png')?

Merci

87
davs

Est-ce vraiment nécessaire pour vous d'avoir un chemin physique?
Par exemple, ImageView.setImageURI() et ContentResolver.openInputStream() vous permettent d’accéder au contenu d’un fichier sans connaître son chemin réel.

51
molnarm

C'est ce que je fais:

Uri selectedImageURI = data.getData();
imageFile = new File(getRealPathFromURI(selectedImageURI));

et:

private String getRealPathFromURI(Uri contentURI) {
    String result;
    Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
    if (cursor == null) { // Source is Dropbox or other similar local file path
        result = contentURI.getPath();
    } else { 
        cursor.moveToFirst(); 
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
        result = cursor.getString(idx);
        cursor.close();
    }
    return result;
}

Remarque: la méthode managedQuery() est obsolète, donc je ne l'utilise pas.

Dernière édition: Amélioration. Nous devrions fermer le curseur !!

175
cesards

@Rene Juuse - ci-dessus dans les commentaires ... Merci pour ce lien!

. le code pour obtenir le chemin réel est un peu différent d'un SDK à un autre, nous avons donc ci-dessous trois méthodes qui traitent de différents SDK.

getRealPathFromURI_API19 (): renvoie le chemin réel de l'API 19 (ou supérieure, mais n'est pas testé). en dessous de 11

public class RealPathUtil {

@SuppressLint("NewApi")
public static String getRealPathFromURI_API19(Context context, Uri uri){
    String filePath = "";
    String wholeID = DocumentsContract.getDocumentId(uri);

     // Split at colon, use second item in the array
     String id = wholeID.split(":")[1];

     String[] column = { MediaStore.Images.Media.DATA };     

     // where id is equal to             
     String sel = MediaStore.Images.Media._ID + "=?";

     Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                               column, sel, new String[]{ id }, null);

     int columnIndex = cursor.getColumnIndex(column[0]);

     if (cursor.moveToFirst()) {
         filePath = cursor.getString(columnIndex);
     }   
     cursor.close();
     return filePath;
}


@SuppressLint("NewApi")
public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
      String[] proj = { MediaStore.Images.Media.DATA };
      String result = null;

      CursorLoader cursorLoader = new CursorLoader(
              context, 
        contentUri, proj, null, null, null);        
      Cursor cursor = cursorLoader.loadInBackground();

      if(cursor != null){
       int column_index = 
         cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
       cursor.moveToFirst();
       result = cursor.getString(column_index);
      }
      return result;  
}

public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri){
           String[] proj = { MediaStore.Images.Media.DATA };
           Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
           int column_index
      = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
           cursor.moveToFirst();
           return cursor.getString(column_index);
}

font: http://hmkcode.com/Android-display-selected-image-and-its-real-path/


MISE À JOUR 2016 Mars

Pour résoudre tous les problèmes de chemin des images, essayez de créer une galerie personnalisée sous Facebook et d'autres applications. En effet, vous ne pouvez utiliser que des fichiers locaux (fichiers réels, ni virtuels ni temporaires). Je résous tous les problèmes liés à cette bibliothèque.

https://github.com/nohana/Laevatein (cette bibliothèque est de prendre une photo depuis un appareil photo ou de choisir dans la galerie, si vous choisissez dans la galerie, il a un tiroir avec des albums et affiche uniquement les fichiers locaux) 

17
luizfelipetx

Note Il s'agit d'une amélioration de @ user3516549 answer et j'ai vérifié sur Moto G3 avec Android 6.0.1
J'ai ce problème alors j'ai essayé de répondre à @ utilisateur3516549 mais dans certains cas, il ne fonctionnait pas correctement . ouvrir qui montre des images récentes lorsque l'utilisateur sélectionne une image de cette liste, nous aurons uri comme 

content://com.Android.providers.media.documents/document/image%3A52530

tandis que si l'utilisateur sélectionne la galerie du tiroir coulissant au lieu de récent, nous aurons uri comme 

content://media/external/images/media/52530

J'ai donc le manipuler dans getRealPathFromURI_API19() 

public static String getRealPathFromURI_API19(Context context, Uri uri) {
        String filePath = "";
        if (uri.getHost().contains("com.Android.providers.media")) {
            // Image pick from recent 
            String wholeID = DocumentsContract.getDocumentId(uri);

            // Split at colon, use second item in the array
            String id = wholeID.split(":")[1];

            String[] column = {MediaStore.Images.Media.DATA};

            // where id is equal to
            String sel = MediaStore.Images.Media._ID + "=?";

            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{id}, null);

            int columnIndex = cursor.getColumnIndex(column[0]);

            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex);
            }
            cursor.close();
            return filePath;
        } else {
            // image pick from gallery 
           return  getRealPathFromURI_BelowAPI11(context,uri)
        }

    }

EDIT: si vous essayez d’obtenir le chemin d’image du fichier dans une carte SD externe en version supérieure, vérifiez ma question

12
Jaiprakash Soni

Il n'y a pas de véritable chemin .

Un Uri avec un schéma content est un descripteur opaque pour certains contenus. Si cette Uri représente un contenu pouvant être ouvert, vous pouvez utiliser ContentResolver et openInputStream() pour obtenir une InputStream sur ce contenu. De même, une variable Uri avec un schéma http ou https ne représente pas un fichier local et vous devez utiliser une API client HTTP pour y accéder.

Seule une variable Uri avec un schéma file identifie un fichier (sauf si le fichier a été déplacé ou supprimé après la création de la variable Uri).

Ce qui est stupide, c’est d’essayer d’obtenir un chemin de système de fichiers en essayant de décoder le contenu de la variable Uri, éventuellement en lançant des sorts pour invoquer $EVIL_DEITY. Au mieux, ce ne sera pas fiable, pour trois raisons:

  1. Les règles de décodage des valeurs Uri peuvent changer au fil du temps, comme avec les versions de version Android, car la structure de Uri représente un détail d'implémentation, pas une interface.

  2. Même si vous obtenez un chemin de système de fichiers, vous n’avez peut-être pas le droit d’accéder au fichier.

  3. Toutes les valeurs Uri ne peuvent pas être décodées via des algorithmes fixes, car de nombreuses applications ont leurs propres fournisseurs et ceux-ci peuvent pointer sur tout, des ressources aux colonnes BLOB aux données devant être transmises en continu depuis Internet

Si vous avez une API limitée qui nécessite un fichier, utilisez la variable InputStream de openInputStream() pour créer une copie de ce contenu. Qu'il s'agisse d'une copie transitoire (par exemple, utilisée pour une opération de téléchargement de fichier, puis supprimée) ou d'une copie durable (par exemple, pour une fonctionnalité "d'importation" de votre application), c'est à vous de décider.

7
CommonsWare

EDIT: Utilisez cette solution ici: https://stackoverflow.com/a/20559175/2033223 Fonctionne parfaitement!

Tout d'abord, merci pour votre solution @luizfelipetx

J'ai un peu changé votre solution. Cela fonctionne pour moi:

public static String getRealPathFromDocumentUri(Context context, Uri uri){
    String filePath = "";

    Pattern p = Pattern.compile("(\\d+)$");
    Matcher m = p.matcher(uri.toString());
    if (!m.find()) {
        Log.e(ImageConverter.class.getSimpleName(), "ID for requested image not found: " + uri.toString());
        return filePath;
    }
    String imgId = m.group();

    String[] column = { MediaStore.Images.Media.DATA };
    String sel = MediaStore.Images.Media._ID + "=?";

    Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            column, sel, new String[]{ imgId }, null);

    int columnIndex = cursor.getColumnIndex(column[0]);

    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }
    cursor.close();

    return filePath;
}

Remarque: Nous avons donc des documents et une image, selon que l’image provienne de la «récente», de la «galerie» ou autre. J'extrais donc d'abord l'ID de l'image avant de la rechercher.

4
Javatar

Salut voici mon code complet pour prendre des images depuis un appareil photo ou une galerie

// Ma déclaration de variable

protected static final int CAMERA_REQUEST = 0;
    protected static final int GALLERY_REQUEST = 1;
    Bitmap bitmap;
    Uri uri;
    Intent picIntent = null;

//Sur clic

if (v.getId()==R.id.image_id){
            startDilog();
        }

// corps de la méthode

private void startDilog() {
    AlertDialog.Builder myAlertDilog = new AlertDialog.Builder(yourActivity.this);
    myAlertDilog.setTitle("Upload picture option..");
    myAlertDilog.setMessage("Where to upload picture????");
    myAlertDilog.setPositiveButton("Gallery", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(Intent.ACTION_GET_CONTENT,null);
            picIntent.setType("image/*");
            picIntent.putExtra("return_data",true);
            startActivityForResult(picIntent,GALLERY_REQUEST);
        }
    });
    myAlertDilog.setNegativeButton("Camera", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            picIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(picIntent,CAMERA_REQUEST);
        }
    });
    myAlertDilog.show();
}

// Et reste des choses

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode==GALLERY_REQUEST){
        if (resultCode==RESULT_OK){
            if (data!=null) {
                uri = data.getData();
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                try {
                    BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    options.inSampleSize = calculateInSampleSize(options, 100, 100);
                    options.inJustDecodeBounds = false;
                    Bitmap image = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    imageofpic.setImageBitmap(image);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }else {
                Toast.makeText(getApplicationContext(), "Cancelled",
                        Toast.LENGTH_SHORT).show();
            }
        }else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }else if (requestCode == CAMERA_REQUEST) {
        if (resultCode == RESULT_OK) {
            if (data.hasExtra("data")) {
                bitmap = (Bitmap) data.getExtras().get("data");
                uri = getImageUri(YourActivity.this,bitmap);
                File finalFile = new File(getRealPathFromUri(uri));
                imageofpic.setImageBitmap(bitmap);
            } else if (data.getExtras() == null) {

                Toast.makeText(getApplicationContext(),
                        "No extras to retrieve!", Toast.LENGTH_SHORT)
                        .show();

                BitmapDrawable thumbnail = new BitmapDrawable(
                        getResources(), data.getData().getPath());
                pet_pic.setImageDrawable(thumbnail);

            }

        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(getApplicationContext(), "Cancelled",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

private String getRealPathFromUri(Uri tempUri) {
    Cursor cursor = null;
    try {
        String[] proj = { MediaStore.Images.Media.DATA };
        cursor = this.getContentResolver().query(tempUri,  proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}
public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}

private Uri getImageUri(YourActivity youractivity, Bitmap bitmap) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    String path = MediaStore.Images.Media.insertImage(youractivity.getContentResolver(), bitmap, "Title", null);
    return Uri.parse(path);
}
1
Tanmay Sahoo

Essaye ça

Néanmoins, si vous rencontrez le problème pour obtenir le vrai chemin, vous pouvez essayer mes réponses. Les réponses ci-dessus ne m'ont pas aidé.

Explication: - Cette méthode obtient l'URI, puis vérifie le niveau de l'API de votre appareil Android. Après quoi, selon le niveau de l'API, le chemin réel sera généré. Le code pour générer le chemin réel est différent selon les niveaux d'API.

Voici ma réponse

0
Sunil

Cela m'a aidé à obtenir uri de la galerie et à convertir en un fichier pour le téléchargement multipart

File file = FileUtils.getFile(this, fileUri);

https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.Java

0