android通过Uri.getPath()获取真实path

我正试图从画廊获得图像。

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

我从这个活动回来后,我有一个数据,其中包含Uri。 看起来像:

 content://media/externalhttp://img.dovov.com1 

我怎么能把这个path转换成真正的path(就像' /sdcard/image.png ')?

谢谢

你真的有必要得到一个物理path吗?
例如, ImageView.setImageURI()ContentResolver.openInputStream()允许您在不知道其真实path的情况下访问文件的内容。

这就是我所做的:

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

和:

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

注意: managedQuery()方法已被弃用,所以我没有使用它。

上次编辑:改进。 我们应该closures光标!

@Rene Juuse – 上面的评论…感谢这个链接!

。 获取真实path的代码与一个SDK有点不同,因此下面我们有三个处理不同SDK的方法。

getRealPathFromURI_API19():返回API 19的实际path(或以上,但未经testing)getRealPathFromURI_API11to18():返回API 11到API 18的实际pathgetRealPathFromURI_below11():返回API实际path11

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

字体: http : //hmkcode.com/android-display-selected-image-and-its-real-path/


更新2016年3月

为了解决所有的图像path问题,我尝试创build一个自定义画廊作为脸书和其他应用程序。 这是因为你只能使用本地文件(真实的文件,而不是虚拟的或临时的),我解决了这个库的所有问题。

https://github.com/nohana/Laevatein (这个图书馆是从相机拍摄照片或select从画廊,如果你从画廊select,他有一个抽屉相册,只显示本地文件)

注意这是对@ user3516549答案的改进,我已经在Android 6.0.1上对Moto G3进行了检查
我有这个问题,所以我已经尝试@ user3516549的答案,但在某些情况下,它不能正常工作。 我发现,在Android 6.0(或以上),当我们开始画廊图像select意图,然后屏幕将打开显示最近的图像,当用户从这个列表中select图像,我们将得到

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

而如果用户从滑动抽屉select画廊,而不是最近那么我们将得到Uri

 content://media/externalhttp://img.dovov.commedia/52530 

所以我在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) } } 

编辑:如果你想获得更高版本的外部SD卡中的文件的图像path,然后检查我的问题

编辑:在这里使用此解决scheme: https : //stackoverflow.com/a/20559175/2033223完美的作品!

首先,感谢您的解决scheme@luizfelipetx

我改变了你的解决scheme一点点。 这适用于我:

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

注:所以我们得到的文件和图像,这取决于,如果图像来自“最近”,“画廊”或什么。 所以我在提取图像ID之前先查看它。

正如实际的程序员所知道的, 没有真正的path

具有contentscheme的Uri是对某些内容的不透明处理。 如果该Uri表示可打开的内容,则可以使用ContentResolveropenInputStream()获取该内容的InputStream 。 同样,具有httphttpsscheme的Uri不代表本地文件,您需要使用HTTP客户端API来访问它。

只有具有filescheme的Uri标识文件(禁止在创buildUri之后移动或删除文件的情况)。

什么愚蠢的人做的是试图通过尝试解码Uri的内容来获得文件系统path,可能与施放法术来调用$EVIL_DEITY 。 充其量,这将是不可靠的,有三个原因:

  1. 解码Uri值的规则可以随着时间而改变,例如Android版本,因为Uri的结构代表实现细节,而不是接口

  2. 即使你得到一个文件系统path,你可能没有权限去访问这个文件

  3. 并不是所有的Uri值都可以通过固定的algorithm来解码,因为许多应用程序都有自己的提供程序,这些值可以指向从资产到BLOB列的所有内容,以及需要从Internet传输的数据

没有任何常识的开发者会走上这条道路。

如果您有一些有限的API需要文件,请使用openInputStream()InputStream复制该内容。 无论是临时副本(例如,用于文件上载操作,然后删除)还是持久副本(例如,用于应用程序的“导入”function)都由您决定。

嗨这里是我完整的代码从相机或图像拍摄图像

//我的variables声明

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

// ONCLICK

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

//方法体

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

//其他的东西

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

这帮助我从图库中获取uri,并将其转换为用于分段上传的文件

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

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