【问题标题】:Get file path from URI从 URI 获取文件路径
【发布时间】:2014-11-17 03:24:16
【问题描述】:

我有图像文件的 Uri。

我使用此代码从 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 应用程序(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();
    }
}

【问题讨论】:

    标签: android android-contentresolver


    【解决方案1】:

    解决方案:

        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/

    【讨论】:

    • DocumentsContract.getDocumentId(uri);未解决,如何组织 DocumentsContract 的导入
    • 你如何为非图像文件实现这一点?
    • 耶稣。 Android API 太糟糕了。
    • 甚至不起作用。在三星 S2 上使用标准图库应用。
    • @Artem 尝试了 Kitkat 及更高版本的代码。不适用于 URI:content://com.android.providers.media.documents/document/image%3A63829。为此,我从 motorola nexus 6 的文件选择器中选择了这张图片
    【解决方案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);
        }
    }
    

    【讨论】:

    • 你如何为非图像文件实现这个?
    【解决方案3】:

    这是我的解决方案,使用了我迄今为止发现的所有技巧,我也在自己的应用程序中使用了这些技巧 (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 中),因此它在不同的地方提供给您。如果您想访问该文件但不关心它真正存在的位置,这很有用。

    【讨论】:

    • 太好了,它适用于所有类型的测试用例。谢谢。
    • @VishalThakkar 能否请您在特殊情况下检查一下,例如 SD 卡?我试图使用我能使用的所有东西......
    • 我没有带 SD 卡的设备。顺便说一句,您可以在 java 中提供上述代码吗?
    • @VishalThakkar Java 会类似。您也可以通过 Java 调用这些函数。无需转换。
    • 如何在 java 中调用它?据我所知,扩展函数不能在 java 中调用。
    【解决方案4】:

    确保您在 Manifest 中授予权限。 在没有授予权限的情况下浪费了 2 个小时尝试各种方法:/

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    

    【讨论】:

      【解决方案5】:

      我认为这应该可行。从路径获取 URI 的通用代码:

      String path = yourAndroidURI.uri.getPath()
      File file = new File(new URI(path));
      

      【讨论】:

      • 例外:URI 不是绝对的:/document/image:16
      【解决方案6】:

      所以我基本上尝试过在堆栈上回答,但这是唯一对我有用的。将 uri 视为图像所指向的位置的“承诺”是很重要的。这并不意味着该位置有文件,但如果您正确询问,您将获得图像。 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();
              }
      

      【讨论】:

        【解决方案7】:

        public static int getIdFromUri(Uri uri, String constantId) { 光标 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 "";
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-05
          • 2020-12-07
          • 2011-03-25
          • 1970-01-01
          相关资源
          最近更新 更多