Obtener nombre de archivo y ruta desde URI desde mediastore

Tengo un onActivityResult regresa de una selección de imagen de mediatore que puedo obtener un URI para una imagen usando lo siguiente:

 Uri selectedImage = data.getData(); 

Convertir esto a una cadena le da esto:

 content://media/external/images/media/47 

O a un camino da:

 /external/images/media/47 

Sin embargo, parece que no puedo encontrar una manera de convertir esto en una ruta absoluta, ya que quiero cargar la imagen en un bitmap sin tener que copiarlo en alguna parte. Sé que esto se puede hacer usando el URI y el solucionador de contenido, pero esto parece romperse al reiniciar el teléfono, supongo que MediaStore no mantiene su numeración igual entre los reinicios.

Debajo de la API 19, use este código para obtener la ruta del archivo desde el URI:

 public String getRealPathFromURI(Context context, Uri contentUri) { Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; 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); } finally { if (cursor != null) { cursor.close(); } } } 

Solo una actualización simple en la primera respuesta: mActivity.managedQuery() ahora está en desuso. He actualizado el código con el nuevo método.

 private String getRealPathFromURI(Uri contentUri) { String[] proj = { MediaStore.Images.Media.DATA }; CursorLoader loader = new CursorLoader(mContext, contentUri, proj, null, null, null); Cursor cursor = loader.loadInBackground(); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); String result = cursor.getString(column_index); cursor.close(); return result; } 

fuente de desarrollo android

No intente encontrar un uri en el sistema de archivos, eso es lento para buscar cosas en la base de datos.

Puedes obtener un bitmap de un uri dando un flujo de entrada a la fábrica como si le dieras un archivo a la fábrica:

 InputStream is = getContentResolver().openInputStream(uri); Bitmap bitmap = BitmapFactory.decodeStream(is); is.close(); 

Para toda la versión que he hecho este método que obtiene una ruta real de uri

  @SuppressLint("NewApi") public static String getFilePath(Context context, Uri uri) throws URISyntaxException { String selection = null; String[] selectionArgs = null; // Uri is different in versions after KITKAT (Android 4.4), we need to if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) { if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); return Environment.getExternalStorageDirectory() + "/" + split[1]; } else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); uri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); } else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("image".equals(type)) { uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } selection = "_id=?"; selectionArgs = new String[]{ split[1] }; } } if ("content".equalsIgnoreCase(uri.getScheme())) { String[] projection = { MediaStore.Images.Media.DATA }; Cursor cursor = null; try { cursor = context.getContentResolver() .query(uri, projection, selection, selectionArgs, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); if (cursor.moveToFirst()) { return cursor.getString(column_index); } } catch (Exception e) { } } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } 

Aquí está mi ejemplo de obtener el nombre de archivo, desde URI como file: // … y content: // …. Funciona para mí no solo con Android MediaStore sino también con aplicaciones de terceros como EzExplorer.

 public static String getFileNameByUri(Context context, Uri uri) { String fileName="unknown";//default fileName Uri filePathUri = uri; if (uri.getScheme().toString().compareTo("content")==0) { Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); if (cursor.moveToFirst()) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data" filePathUri = Uri.parse(cursor.getString(column_index)); fileName = filePathUri.getLastPathSegment().toString(); } } else if (uri.getScheme().compareTo("file")==0) { fileName = filePathUri.getLastPathSegment().toString(); } else { fileName = fileName+"_"+filePathUri.getLastPathSegment(); } return fileName; } 

Buenas respuestas existentes, algunas de las cuales solía encontrar la mía:

Tengo que obtener el camino de los URI y obtener el URI de las rutas, y Google tiene dificultades para diferenciarlo para cualquiera que tenga el mismo problema (por ejemplo, para obtener la miniatura de MediaStore de un video cuya ubicación física ya tener). El primero:

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

El último (que hago para videos, pero también se puede usar para Audio o Archivos u otros tipos de contenido almacenado al sustituir MediaStore.Audio (etc) por 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; } 

Básicamente, la columna DATA de MediaStore (o cualquiera de las subsecciones de la que está consultando) almacena la ruta del archivo, por lo que puede usar lo que sabe para buscar ese campo DATA o usar el campo para buscar cualquier otra cosa que desee .

A continuación, utilizo el Scheme como se Scheme arriba para descubrir qué hacer con mis datos:

  private boolean getSelectedVideo(Intent imageReturnedIntent, boolean fromData) { Uri selectedVideoUri; //Selected image returned from another activity // A parameter I pass myself to know whether or not I'm being "shared via" or // whether I'm working internally to my app (fromData = working internally) if(fromData){ selectedVideoUri = imageReturnedIntent.getData(); } else { //Selected image returned from SEND intent // which I register to receive in my manifest // (so people can "share via" my app) selectedVideoUri = (Uri)getIntent().getExtras().get(Intent.EXTRA_STREAM); } Log.d(TAG,"SelectedVideoUri = " + selectedVideoUri); String filePath; String scheme = selectedVideoUri.getScheme(); ContentResolver contentResolver = getContentResolver(); long videoId; // If we are sent file://something or content://org.openintents.filemanager/mimetype/something... if(scheme.equals("file") || (scheme.equals("content") && selectedVideoUri.getEncodedAuthority().equals("org.openintents.filemanager"))){ // Get the path filePath = selectedVideoUri.getPath(); // Trim the path if necessary // openintents filemanager returns content://org.openintents.filemanager/mimetype//mnt/sdcard/xxxx.mp4 if(filePath.startsWith("/mimetype/")){ String trimmedFilePath = filePath.substring("/mimetype/".length()); filePath = trimmedFilePath.substring(trimmedFilePath.indexOf("/")); } // Get the video ID from the path videoId = getVideoIdFromFilePath(filePath, contentResolver); } else if(scheme.equals("content")){ // If we are given another content:// URI, look it up in the media provider videoId = Long.valueOf(selectedVideoUri.getLastPathSegment()); filePath = getFilePathFromContentUri(selectedVideoUri, contentResolver); } else { Log.d(TAG,"Failed to load URI " + selectedVideoUri.toString()); return false; } return true; } 

Ninguna de estas respuestas funcionó para mí en todos los casos. Tuve que ir directamente a la Documentación de Google https://developer.android.com/guide/topics/providers/document-provider.html sobre este tema y encontré este útil método:

 private Bitmap getBitmapFromUri(Uri uri) throws IOException { ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r"); FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor); parcelFileDescriptor.close(); return image; } 

Puede usar este bitmap para mostrarlo en una Vista de imagen.

Solución para aquellos que tienen problemas luego de mudarse a KitKat:

“Esto obtendrá la ruta del archivo desde MediaProvider, DownloadsProvider y ExternalStorageProvider, mientras recurre al método no oficial de ContentProvider” https://stackoverflow.com/a/20559175/690777

Como ManageQuery ha quedado obsoleto, puedes intentar:

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

Aquí le mostraré cómo crear un botón BROWSE, que cuando haga clic en él, abrirá la tarjeta SD, seleccionará un Archivo y como resultado obtendrá el nombre del archivo y la ruta del archivo del archivo seleccionado. uno:

Un botón que golpearás

 browse.setOnClickListener(new OnClickListener() { public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_PICK); Uri startDir = Uri.fromFile(new File("/sdcard")); startActivityForResult(intent, PICK_REQUEST_CODE); } }); 

La función que obtendrá el nombre de archivo resuelto y la ruta de archivo

 protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == PICK_REQUEST_CODE) { if (resultCode == RESULT_OK) { Uri uri = intent.getData(); if (uri.getScheme().toString().compareTo("content")==0) { Cursor cursor =getContentResolver().query(uri, null, null, null, null); if (cursor.moveToFirst()) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data" Uri filePathUri = Uri.parse(cursor.getString(column_index)); String file_name = filePathUri.getLastPathSegment().toString(); String file_path=filePathUri.getPath(); Toast.makeText(this,"File Name & PATH are:"+file_name+"\n"+file_path, Toast.LENGTH_LONG).show(); } } } } } 

Después de obtener una imagen de la galería, solo pase el URI en el siguiente método solo para Android 4.4 (KitKat):

 public String getPath(Uri contentUri) {// Will return "image:x*" String wholeID = DocumentsContract.getDocumentId(contentUri); // 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 = getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[] { id }, null); String filePath = ""; int columnIndex = cursor.getColumnIndex(column[0]); if (cursor.moveToFirst()) { filePath = cursor.getString(columnIndex); } cursor.close(); return filePath; } 

Esta solución funciona para todos los casos:

En algunos casos, es muy difícil obtener la ruta desde la URL. Entonces, ¿por qué necesitas el camino? Para copiar el archivo en otro lugar? No necesitas el camino.

 public void SavePhotoUri (Uri imageuri, String Filename){ File FilePath = context.getDir(Environment.DIRECTORY_PICTURES,Context.MODE_PRIVATE); try { Bitmap selectedImage = MediaStore.Images.Media.getBitmap(context.getContentResolver(), imageuri); String destinationImagePath = FilePath + "/" + Filename; FileOutputStream destination = new FileOutputStream(destinationImagePath); selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, destination); destination.close(); } catch (Exception e) { Log.e("error", e.toString()); } } 

prueba esta ruta del archivo get image desde Uri

 public void getImageFilePath(Context context, Uri uri) { Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); cursor.moveToFirst(); String image_id = cursor.getString(0); image_id = image_id.substring(image_id.lastIndexOf(":") + 1); cursor.close(); cursor = context.getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null); cursor.moveToFirst(); String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); cursor.close(); upLoadImageOrLogo(path); } 

Aquí obtienes el nombre del archivo

 String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; Uri uri = data.getData(); String fileName = null; ContentResolver cr = getActivity().getApplicationContext().getContentResolver(); Cursor metaCursor = cr.query(uri, projection, null, null, null); if (metaCursor != null) { try { if (metaCursor.moveToFirst()) { fileName = metaCursor.getString(0); } } finally { metaCursor.close(); } } 

Simple y fácil. ¡Puedes hacer esto desde el URI como abajo!

 public void getContents(Uri uri) { Cursor vidCursor = getActivity.getContentResolver().query(uri, null, null, null, null); if (vidCursor.moveToFirst()) { int column_index = vidCursor .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); Uri filePathUri = Uri.parse(vidCursor .getString(column_index)); String video_name = filePathUri.getLastPathSegment().toString(); String file_path=filePathUri.getPath(); Log.i("TAG", video_name + "\b" file_path); } } 

API 19 y superiores , la ruta del archivo de imagen de Uri funciona perfectamente. También compruebo esta última Oreo API 27 .

 public String getImageFilePath(Uri uri) { String path = null, image_id = null; Cursor cursor = getContentResolver().query(uri, null, null, null, null); if (cursor != null) { cursor.moveToFirst(); image_id = cursor.getString(0); image_id = image_id.substring(image_id.lastIndexOf(":") + 1); cursor.close(); } Cursor cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null); if (cursor!=null) { cursor.moveToFirst(); path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); cursor.close(); } return path; } 

Versión ligeramente modificada de @PercyPercy: no arroja y simplemente devuelve nulo si algo sale mal :

 public String getPathFromMediaUri(Context context, Uri uri) { String result = null; String[] projection = { MediaStore.Images.Media.DATA }; Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); int col = cursor.getColumnIndex(MediaStore.Images.Media.DATA); if (col >= 0 && cursor.moveToFirst()) result = cursor.getString(col); cursor.close(); return result; } 

Como complemento, si necesita ver si existe un archivo antes de intentar abrir una secuencia de entrada, puede usar el DocumentsContract.

(Código de Kotlin)

 var iStream = null if(DocumentsContract.isDocumentUri(context,myUri)) { val pfd: ParcelFileDescriptor? = context.contentResolver.openFileDescriptor( myUri, "r") ?: return null iStream = ParcelFileDescriptor.AutoCloseInputStream(pfd) } 

Como las respuestas anteriores no me funcionaron, aquí está la solución que funcionó para mí:

Para niveles de API> 19 y < = 19.

Este método cubre todos los casos para obtener filePath de uri

 /** * Get a file path from a Uri. This will get the the path for Storage Access * Framework Documents, as well as the _data field for the MediaStore and * other file-based ContentProviders. * * @param context The activity. * @param uri The Uri to query. * @author paulburke */ public static String getPath(final Context context, final Uri uri) { // DocumentProvider if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; }else{ Toast.makeText(context, "Could not get file path. Please try again", Toast.LENGTH_SHORT).show(); } } // DownloadsProvider else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } else { contentUri = MediaStore.Files.getContentUri("external"); } final String selection = "_id=?"; final String[] selectionArgs = new String[] { split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } 

Prueba esto

Aún así, si obtiene el problema para obtener la ruta real, puede probar mis respuestas. Las respuestas anteriores no me ayudaron.

Explicación : – Este método obtiene el URI y luego verifica el nivel de la API de su dispositivo Android luego de que, de acuerdo con el nivel de API, generará la ruta real. El código para generar un método de ruta real es diferente según los niveles de API.

  1. método para obtener la ruta real de URI

     @SuppressLint("ObsoleteSdkInt") public String getPathFromURI(Uri uri){ String realPath=""; // SDK < API11 if (Build.VERSION.SDK_INT < 11) { String[] proj = { MediaStore.Images.Media.DATA }; @SuppressLint("Recycle") Cursor cursor = getContentResolver().query(uri, proj, null, null, null); int column_index = 0; String result=""; if (cursor != null) { column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); realPath=cursor.getString(column_index); } } // SDK >= 11 && SDK < 19 else if (Build.VERSION.SDK_INT < 19){ String[] proj = { MediaStore.Images.Media.DATA }; CursorLoader cursorLoader = new CursorLoader(this, uri, proj, null, null, null); Cursor cursor = cursorLoader.loadInBackground(); if(cursor != null){ int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); realPath = cursor.getString(column_index); } } // SDK > 19 (Android 4.4) else{ 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 = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{ id }, null); int columnIndex = 0; if (cursor != null) { columnIndex = cursor.getColumnIndex(column[0]); if (cursor.moveToFirst()) { realPath = cursor.getString(columnIndex); } cursor.close(); } } return realPath; } 
  2. Usa este método así

     Log.e(TAG, "getRealPathFromURI: "+getPathFromURI(your_selected_uri) ); 

Salida:-

04-06 12: 39: 46.993 6138-6138 / com.app.qtm E / tag: getRealPathFromURI: /storage/emulated/0/Video/avengers_infinity_war_4k_8k-7680×4320.jpg

Perfectamente trabajando para mí el código fijo de esta publicación :

  public static String getRealPathImageFromUri(Uri uri) { String fileName =null; if (uri.getScheme().equals("content")) { try (Cursor cursor = MyApplication.getInstance().getContentResolver().query(uri, null, null, null, null)) { if (cursor.moveToFirst()) { fileName = cursor.getString(cursor.getColumnIndexOrThrow(ediaStore.Images.Media.DATA)); } } catch (IllegalArgumentException e) { Log.e(mTag, "Get path failed", e); } } return fileName; } 

Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);