Получить имя файла и путь от URI от медиастора

У меня есть onActivityResult возвращающийся из выбора изображения медиастара, который я могу получить URI для изображения, используя следующее:

 Uri selectedImage = data.getData(); 

Преобразование этого в строку дает следующее:

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

Или на путь дает:

 /external/images/media/47 

Однако я не могу найти способ преобразовать это в абсолютный путь, так как хочу загрузить изображение в bitmap без необходимости его копировать. Я знаю, что это можно сделать с помощью URI и разрешения контента, но это, похоже, прерывает перезагрузку телефона, я полагаю, что MediaStore не сохраняет свою нумерацию между перезагрузками.

Ниже API 19 используйте этот код, чтобы получить путь к файлу из 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(); } } } 

Простое обновление первого ответа: mActivity.managedQuery() теперь устарел. Я обновил код с помощью нового метода.

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

Исходный код

Не пытайтесь найти uri в файловой системе, это медленнее, чтобы искать вещи в базе данных.

Вы можете получить bitmap из uri, предоставив входной stream на завод, как вы даете файл на завод:

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

Для версии «Все» я сделал этот метод, который получает реальный путь от 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()); } 

Вот мой пример получения имени файла из URI, например file: // … и content: // …. Это работает для меня не только с Android MediaStore, но и с приложениями из третьей части, такими как 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; } 

Хорошие существующие ответы, некоторые из которых я придумывал самостоятельно:

Я должен получить путь от URI и получить URI с пути, и Google нелегко сказать разницу, так что для тех, кто имеет такую ​​же проблему (например, чтобы получить эскиз из MediaStore видео, физическое местоположение которого вы уже иметь). Бывший:

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

Последнее (что я делаю для видео, но также можно использовать для аудио или файлов или других типов хранимого содержимого, заменив MediaStore.Audio (и т. Д.) Для 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; } 

В основном, столбец DATA в MediaStore (или какой-либо его подразделение, который вы запрашиваете) хранит путь к файлу, поэтому вы либо используете то, что знаете, для поиска этого поля DATA , либо используете поле для поиска того, что хотите ,

Затем я использую Scheme как указано выше, чтобы выяснить, что делать с моими данными:

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

Ни один из этих ответов не работал для меня во всех случаях. Мне пришлось перейти непосредственно к документации Google https://developer.android.com/guide/topics/providers/document-provider.html по этой теме и нашел этот полезный метод:

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

Вы можете использовать это bitmap, чтобы отобразить его в представлении изображения.

Решение для тех, у кого проблемы после переезда в KitKat:

«Это позволит получить путь к файлу из MediaProvider, DownloadsProvider и ExternalStorageProvider, возвращаясь к неофициальному методу ContentProvider» https://stackoverflow.com/a/20559175/690777

Поскольку managedQuery устарел, вы можете попробовать:

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

Здесь я покажу вам, как создать кнопку BROWSE, которая, когда вы нажмете, откроет SD-карту, вы выберете файл, и в результате вы получите имя файла и путь к файлу выбранного один:

Кнопка, на которую вы нажмете

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

Функция, которая получит имя и путь к итоговому файлу

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

Получив изображение из галереи, просто передайте URI в приведенном ниже методе только для 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; } 

Это решение работает для каждого случая:

Слишком сложно в некоторых случаях получить путь от URL-адреса. Тогда зачем вам путь? Скопировать файл в другое место? Вам не нужен путь.

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

попробуйте получить путь к файлу изображения из 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); } 

Здесь вы получите имя файла

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

Простой и легкий. Вы можете сделать это из URI, как показано ниже!

 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 и выше , путь файла изображений из Uri отлично работает. Я также проверяю этот последний API Oreo 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; } 

Немного измененная версия @PercyPercy – она ​​не бросает и просто возвращает null, если что-то пойдет не так :

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

В качестве надстройки, если вам нужно проверить, существует ли файл до того, как вы попытаетесь открыть входной stream, вы можете использовать DocumentContract.

(Код Котлина)

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

Поскольку приведенные выше ответы не сработали для меня, вот решение, которое сработало для меня:

Для обоих уровней> 19 и <= 19 API.

Этот метод охватывает все случаи, чтобы получить filePath из 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; } 

Попробуй это

Тем не менее, если вы получаете проблему, чтобы получить реальный путь, вы можете попробовать мои ответы. Выше ответы мне не помогли.

Объяснение : – Этот метод получает URI, а затем проверяет уровень API вашего устройства Android после этого, согласно уровню API, он будет генерировать Real-путь. Код для генерации метода реального пути отличается в соответствии с уровнями API.

  1. метод для получения Реального пути из 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. Используйте этот метод следующим образом:

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

Вывод:-

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

Отлично работает для меня фиксированный код из этого сообщения :

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

Interesting Posts

Получение текущего пользователя Windows в веб-приложении Java EE для целей единого входа

Json.NET добавляет обратную косую черту при возврате сериализованной строки json

Как включить имя сеанса экрана в hardstatus?

может ли value.var в dcast быть списком или иметь несколько переменных значений?

Как отобразить текущую версию моего приложения для пользователя?

Что эквивалентно memset в C #?

Может ли терминал PowerShell по умолчанию хранить историю команд?

Несколько версий Java, работающих одновременно под Windows

Как увеличить производительность Mac OS X?

Как замедлить скорость моего Wi-Fi в Thomson Speedtouch

Как регистрировать все брошенные исключения?

Показать вкладки в полноэкранном режиме Chrome?

Как выбрать целые слова в режиме мыши Tmux?

Преобразование символов, акцентированных букв на английский алфавит

R tm package vcorpus: ошибка в преобразовании корпуса в кадр данных

Давайте будем гением компьютера.