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 。
具有content
scheme的Uri
是对某些内容的不透明处理。 如果该Uri
表示可打开的内容,则可以使用ContentResolver
和openInputStream()
获取该内容的InputStream
。 同样,具有http
或https
scheme的Uri
不代表本地文件,您需要使用HTTP客户端API来访问它。
只有具有file
scheme的Uri
标识文件(禁止在创buildUri
之后移动或删除文件的情况)。
什么愚蠢的人做的是试图通过尝试解码Uri
的内容来获得文件系统path,可能与施放法术来调用$EVIL_DEITY
。 充其量,这将是不可靠的,有三个原因:
-
解码
Uri
值的规则可以随着时间而改变,例如Android版本,因为Uri
的结构代表实现细节,而不是接口 -
即使你得到一个文件系统path,你可能没有权限去访问这个文件
-
并不是所有的
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);