通过 Uri.getPath()获取真实路径

我想从画廊得到图像。

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

After I returned from this activity I have a data, which contains Uri. It looks like:

content://media/external/images/1

如何将这个路径转换为真正的路径(就像‘ /sdcard/image.png’) ?

谢谢

245864 次浏览

你真的有必要走物理路径吗?
例如,ImageView.setImageURI()ContentResolver.openInputStream()允许您在不知道文件实际路径的情况下访问文件的内容。

这就是我的工作:

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()方法已被弃用,因此我不使用它。

最后一次编辑: 改进。我们应该关闭光标! !

@ Rene Juuse-楼上评论... 谢谢这个链接!

. 得到实际路径的代码在不同的 SDK 之间有所不同,所以下面我们有三个方法来处理不同的 SDK。

getRealPathFromURI_API19(): returns real path for API 19 (or above but not tested) GetRealPathFromURI _ API11to18() : 返回 API 11到 API 18的实际路径 GetRealPathFromURI _ below11() : 返回 API 低于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);
}

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


UPDATE 2016 March

为了解决所有的图像路径问题,我尝试创建一个自定义图库作为脸谱网和其他应用程序。这是因为您可以只使用本地文件(实际文件,而不是虚拟或临时) ,我解决了这个库的所有问题。

Https://github.com/nohana/laevatein (这个库可以从相机中拍照或从画廊中选择,如果你从画廊中选择,他有一个装有相册的抽屉,只显示本地文件)

注意 这是 @ user3516549回答的一个改进,我已经在 MotoG3的 Android 6.0.1上检查过了
我有这个问题,所以我尝试回答@user3516549,但在某些情况下,它不能正常工作。 我发现,在 Android 6.0(或更高版本)中,当我们开始画廊图像选择意图时,当用户从这个列表中选择图像时,会打开一个显示最近图像的屏幕,我们将得到 uri 作为

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

而如果用户选择画廊从滑动抽屉,而不是最近,那么我们将得到 URI 作为

content://media/external/images/media/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)
}
}

编辑1: 如果你试图在外部 sdcard 中获得更高版本的文件的图像路径,那么检查 < a href = “ https://stackoverflow. com/questions/42110882/”> 我的问题

EDIT2 给你是处理虚拟文件和主机以外的完整代码,我已经用 content://com.adobe.scan.android.documents/document/测试过这种方法

“嗨”这里是我从照相机或画廊获取图像的完整代码

//我的变量声明

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

//点击

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

编辑: 在这里使用这个解决方案: https://stackoverflow.com/a/20559175/2033223 效果很好!

First of, thank for your solution @luizfelipetx

I changed your solution a little bit. This works for me:

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。

这有助于我得到从画廊和转换为一个文件的多部分上传

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

Https://github.com/ipaulpro/afilechooser/blob/master/afilechooser/src/com/ipaulpro/afilechooser/utils/fileutils.java

一个简单和最好的方法复制文件到真正的路径,然后得到他们的路径我检查它10个设备上的 机器人 API-16到 API-30工作良好。

@Nullable
public static String createCopyAndReturnRealPath(
@NonNull Context context, @NonNull Uri uri) {
final ContentResolver contentResolver = context.getContentResolver();
if (contentResolver == null)
return null;


// Create file path inside app's data dir
String filePath = context.getApplicationInfo().dataDir + File.separator + "temp_file";
File file = new File(filePath);
try {
InputStream inputStream = contentResolver.openInputStream(uri);
if (inputStream == null)
return null;
OutputStream outputStream = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0)
outputStream.write(buf, 0, len);
outputStream.close();
inputStream.close();
} catch (IOException ignore) {
return null;
}
return file.getAbsolutePath();
}

这个代码对我在机器人11和12中起作用

private static String getRealPathFromURI(Uri uri, Context context) {
Uri returnUri = uri;
Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
String name = (returnCursor.getString(nameIndex));
String size = (Long.toString(returnCursor.getLong(sizeIndex)));
File file = new File(context.getFilesDir(), name);
try {
InputStream inputStream = context.getContentResolver().openInputStream(uri);
FileOutputStream outputStream = new FileOutputStream(file);
int read = 0;
int maxBufferSize = 1 * 1024 * 1024;
int bytesAvailable = inputStream.available();
        

//int bufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
        

final byte[] buffers = new byte[bufferSize];
while ((read = inputStream.read(buffers)) != -1) {
outputStream.write(buffers, 0, read);
}
Log.e("File Size", "Size " + file.length());
inputStream.close();
outputStream.close();
Log.e("File Path", "Path " + file.getPath());
Log.e("File Size", "Size " + file.length());
} catch (Exception e) {
Log.e("Exception", e.getMessage());
}
return file.getPath();
}