我有Uri for Image文件。
我使用此代码从Uri获取文件路径:
public String getRealPathFromURI(Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = mContext.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} catch (Exception e) {
Log.message(e.getMessage());
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
如果我从图库应用(Android 4.4.2,arm-emu)中选择图片,
uri.getPath = /external/images/media/16 and it work's fine (My file path: /storage/sdcard/Download/0_cf15a_7800a7e5_orig.jpg)
如果我从Documents app(Android 4.4.2,arm-emu)中选择图像,
I have uri.getPath = /document/image:16 and function getRealPathFromURI returns null.
如何为两个动作返回正确的文件路径?
我的代码是: -
@Override
public void onClick(View v) {
final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "Photohunt" + File.separator);
root.mkdirs();
final String fname = Common.getUniqueImageFilename();
final File sdImageMainDirectory = new File(root, fname);
outputFileUri = Uri.fromFile(sdImageMainDirectory);
// Camera.
final List<Intent> cameraIntents = new ArrayList<Intent>();
final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final PackageManager packageManager = mContext.getPackageManager();
final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for(ResolveInfo res : listCam) {
final String packageName = res.activityInfo.packageName;
final Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(packageName);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
cameraIntents.add(intent);
}
// Filesystem.
final Intent galleryIntent = new Intent();
galleryIntent.setType("image/*");
galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
// Chooser of filesystem options.
final Intent chooserIntent = Intent.createChooser(galleryIntent, "Select Source");
// Add the camera options.
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
startActivityForResult(chooserIntent, PICTURE_REQUEST_CODE);
}
处理活动结果:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(resultCode == Activity.RESULT_OK)
{
if(requestCode == PICTURE_REQUEST_CODE)
{
final boolean isCamera;
if(data == null)
{
isCamera = true;
}
else
{
final String action = data.getAction();
if(action == null)
{
isCamera = false;
}
else
{
isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
}
}
Uri selectedImageUri;
if(isCamera)
{
selectedImageUri = outputFileUri;
}
else
{
selectedImageUri = data == null ? null : data.getData();
}
Log.variable("uri", selectedImageUri.getPath());
ConfirmImageFragment fragment = new ConfirmImageFragment(selectedImageUri, mContestId);
FragmentTransaction transaction = getSherlockActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
将所选文件加载到ImageView中对于两种状态都可以正常工作:
private void loadImage() {
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), mUri);
mImage.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
答案 0 :(得分:22)
解决方案:
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/
答案 1 :(得分:2)
接受答案的更简单版本,它将检测API级别并使用正确的方法:
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getFilePath(Context context, Uri uri)
{
int currentApiVersion;
try
{
currentApiVersion = android.os.Build.VERSION.SDK_INT;
}
catch(NumberFormatException e)
{
//API 3 will crash if SDK_INT is called
currentApiVersion = 3;
}
if (currentApiVersion >= Build.VERSION_CODES.KITKAT)
{
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;
}
else if (currentApiVersion <= Build.VERSION_CODES.HONEYCOMB_MR2 && currentApiVersion >= Build.VERSION_CODES.HONEYCOMB)
{
String[] proj = {MediaStore.Images.Media.DATA};
String result = null;
CursorLoader cursorLoader = new CursorLoader(
context,
uri, 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;
}
else
{
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
int column_index
= cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
答案 2 :(得分:1)
确保您在Manifest中获得许可。 在没有授予权限的情况下浪费了2个小时尝试各种方法:/
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
答案 3 :(得分:0)
我认为这应该有效。从路径获取URI的通用代码:
String path = yourAndroidURI.uri.getPath()
File file = new File(new URI(path));
答案 4 :(得分:0)
所以我基本上试过在堆栈上回答,但这是唯一对我有用的。重要的是要把uri视为一个承诺&#34;图像生活在指向的地方。这并不意味着该位置有文件,但如果您正确询问,您将获得一张图片。 attachementPath是图像的路径(可以像常规文件一样使用)。见下文:
try {
InputStream input = getActivity().getContentResolver().openInputStream(imageUri);
File file = new File(getActivity().getCacheDir(), "cacheFileAppeal.png");
try {
OutputStream output = new FileOutputStream(file);
try {
try {
byte[] buffer = new byte[4 * 1024]; // or other buffer size
int read;
if (input != null) {
while ((read = input.read(buffer)) != -1) {
output.write(buffer, 0, read);
}
}
output.flush();
} finally {
output.close();
attachmentPath = file.getAbsolutePath();
}
} catch (Exception e) {
e.printStackTrace(); // handle exception, define IOException and others
}
} finally {
try {
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
答案 5 :(得分:0)
public static int getIdFromUri(Uri uri,String constantId) { Cursor c = ContentMaster.getContentResolver()。query(uri,new String [] {constantId},null,null,null);
int res = -1;
if(c != null && c.getCount() > 0)
{
c.moveToFirst();
res = c.getInt(0);
c.close();
}
return res;
}
public static Uri getUriWithId(Uri baseUri,int contactId)
{
Uri u = ContentUris.withAppendedId(baseUri, contactId);
if(u != null)
return u;
return Uri.EMPTY;
}
public static String getRealPathFromURI(Uri uri)
{
if(uri == null)
return "";
if ("file".equalsIgnoreCase(uri.getScheme()))
return uri.getPath();
String[] pro = { MediaStore.Images.Media.DATA };
String result = null;
Cursor cursor;
if(VERSION.SDK_INT > 18)
{
//String wholeID = DocumentsContract.getDocumentId(uri);
//String id = wholeID.split(":")[1];
String id = String.valueOf(getIdFromUri(uri, Images.Media._ID));
String[] column = { MediaStore.Images.Media.DATA };
String where = MediaStore.Images.Media._ID + "=?";
Uri u = uri;
if(isMediaDocument(uri))
{
if (getUriMediaDocumentType(uri).equals("image"))
{
if(isExternalStorageDocument(uri))
u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
else
u = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
}
else if (getUriMediaDocumentType(uri).equals("video"))
{
if(isExternalStorageDocument(uri))
u = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
else
u = MediaStore.Video.Media.INTERNAL_CONTENT_URI;
}
else if (getUriMediaDocumentType(uri).equals("audio"))
{
if(isExternalStorageDocument(uri))
u = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
else
u = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
}
}
else if(isDownloadsDocument(uri))
{
u = getUriWithId(Uri.parse("content://downloads/public_downloads"), Integer.getInteger(id));
}
cursor = getContentResolver().query(u, column, where, new String[]{id}, null);
}
else if(VERSION.SDK_INT > 10)
{
CursorLoader cursorLoader = new CursorLoader(SystemMaster.getContext(), uri, pro, null, null, null);
cursor = cursorLoader.loadInBackground();
}
else
{
cursor = SystemMaster.getContext().getContentResolver().query(uri, pro, null, null, null);
}
if(cursor != null && cursor.getCount() > 0)
{
cursor.moveToFirst();
result = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
}
return result;
}
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());
}
public static String getUriMediaDocumentType(Uri uri)
{
if(isMediaDocument(uri))
{
//TODO
return "image";
}
return "";
}
答案 6 :(得分:0)
答案 7 :(得分:0)
这是我的解决方案,使用了到目前为止发现的所有技巧,我也在自己的应用程序中使用了这些技巧(here):
FileUtilEx.kt
fun Closeable?.closeSilently() {
if (this != null) try {
this.close()
} catch (e: Exception) {
}
}
object FileUtilEx {
fun getFilePathFromUri(context: Context, uri: Uri, includeUriMappingTechnique: Boolean = true, tryToGetWritePermission: Boolean = false): ClosableFileHolder? {
var file: File
uri.path?.let {
file = File(it)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
}
if (uri.scheme == "file") {
try {
val jUri = java.net.URI(uri.scheme, uri.schemeSpecificPart, uri.fragment)
file = File(jUri)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
} catch (e: Exception) {
}
try {
val uriStr = uri.toString()
val decodePath = URLDecoder.decode(uriStr, "UTF-8")
file = File(decodePath)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
} catch (e: UnsupportedEncodingException) {
}
}
val authority = uri.authority
if (uri.scheme == "content") {
//handles "Files" app, and many others
getRealPathFromUri(context, uri)?.let {
file = File(it)
if (file.exists() && file.canRead()) {
// Log.d("AppLog", "got real file")
return ClosableFileHolder(file)
}
}
}
if (includeUriMappingTechnique) {
val fileUsingUriMappingTechnique = getFileUsingUriMappingTechnique(context, uri, tryToGetWritePermission)
if (fileUsingUriMappingTechnique != null)
return fileUsingUriMappingTechnique
}
getFilePathFromDocumentUri(context, uri)?.let { filePath ->
file = File(filePath)
if (file.exists() && file.canRead())
return ClosableFileHolder(file)
}
return null
}
private fun getRealPathFromUri(context: Context, contentUri: Uri): String? {
try {
context.contentResolver.query(contentUri, arrayOf(MediaStore.Images.Media.DATA), null, null, null)?.use { cursor ->
val columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
if (columnIndex < 0 || cursor.count <= 0)
return null
cursor.moveToFirst()
return cursor.getString(columnIndex)
}
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
fun getFileUsingUriMappingTechnique(context: Context, androidUri: Uri, tryToGetWritePermission: Boolean = false): ClosableFileHolder? {
var parcelFileDescriptor: ParcelFileDescriptor? = null
for (i in 0..1)
try {
parcelFileDescriptor = context.contentResolver.openFileDescriptor(androidUri, if (tryToGetWritePermission && i == 0) "w" else "r")
if (parcelFileDescriptor != null) {
val fd: Int = parcelFileDescriptor.fd
val linkFileName = "/proc/self/fd/$fd"
if (VERSION.SDK_INT >= VERSION_CODES.O) {
val realFilePath = Files.readSymbolicLink(Paths.get(linkFileName))
val file = realFilePath.toFile()
if (file.exists() && file.canRead()) {
parcelFileDescriptor.closeSilently()
return ClosableFileHolder(file)
}
}
val file = File(linkFileName)
if (file.exists() && file.canRead())
return ClosableFileHolder(file, parcelFileDescriptor)
parcelFileDescriptor.closeSilently()
}
} catch (e: Exception) {
parcelFileDescriptor.closeSilently()
parcelFileDescriptor = null
}
return null
}
private fun getFilePathFromDocumentUri(context: Context, uri: Uri): String? {
// https://stackoverflow.com/questions/5657411/android-getting-a-file-uri-from-a-content-uri
// DocumentProvider
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && DocumentFile.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if ("com.android.externalstorage.documents" == uri.authority) {
val docId = DocumentsContract.getDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val type = split[0]
// This is for checking Main Memory
return if ("primary".equals(type, ignoreCase = true)) {
if (split.size > 1) {
Environment.getExternalStorageDirectory().absolutePath + "/" + split[1] + "/"
} else {
Environment.getExternalStorageDirectory().absolutePath + "/"
}
// This is for checking SD Card
} else {
"storage" + "/" + docId.replace(":", "/")
}
}
}
return null
}
}
ClosableFileHolder.kt
class ClosableFileHolder(val file: File, private val parcelFileDescriptor: ParcelFileDescriptor? = null) : Closeable {
fun isUsingUriMappingTechnique(): Boolean = parcelFileDescriptor != null
override fun close() {
parcelFileDescriptor.closeSilently()
}
protected fun finalize() {
parcelFileDescriptor.closeSilently()
}
}
用法:
FileUtilEx.getFilePathFromUri(context, uri, false)?.use {
val file = it.file
...
}
如果要访问文件,可以使用tryToGetWritePermission
参数,但是实际上它通常不可用(例如在SAF中),因此可以在其他位置使用它。如果您想访问文件但不关心文件实际存在的位置,这很有用。