【问题标题】:Get path from Uri从 Uri 获取路径
【发布时间】:2018-07-05 18:58:45
【问题描述】:

我正在让用户使用存储访问框架文档选择内部或外部存储(SD 卡)的存储。

用户选择目录后,我要检查用户选择的目录是否属于特定存储(内部或外部存储)的根文件夹。

这就是我试图实现这一目标的方式,这就是我迄今为止所取得的成就-

public void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (resultCode == RESULT_OK && requestCode == 42) {
            Uri treeUri = data.getData();
          if (!wrong_directory_selected(treeUri, Context)) {
               // Permission granted for the Directory as required by me

                } else {
                    // Permission not granted for the Directory as required by me
                }
            } 
        }
    }

public boolean wrong_directory_selected(Uri uri, Context con)
    {
        final File uri_path=new File(FileUtil.getFullPathFromTreeUri(uri,con.getApplicationContext()));
        if(uri_path!=null)
        {
            if(uri_path.getName().toLowerCase().equals(new File(PathForWhichPermissionNeeded).getName().toLowerCase()))
            {

                return false;
            }
        }

        return  true;
    }

这是我的FileUtil 班级-

public final class FileUtil {


    private static final String PRIMARY_VOLUME_NAME = "primary";




    @Nullable
    public static String getFullPathFromTreeUri(@Nullable final Uri treeUri, Context con)
    {

        if (treeUri == null)
        {
            return null;
        }
        String volumePath = getVolumePath(getVolumeIdFromTreeUri(treeUri),con);

        if (volumePath == null)
        {
            return File.separator;
        }
        if (volumePath.endsWith(File.separator))
        {
            volumePath = volumePath.substring(0, volumePath.length() - 1);

        }

        String documentPath = getDocumentPathFromTreeUri(treeUri);
        Log.e("DocumentPath",documentPath);
        if (documentPath.endsWith(File.separator))
        {
            documentPath = documentPath.substring(0, documentPath.length() - 1);

        }

        if (documentPath.length() > 0)
        {
            if (documentPath.startsWith(File.separator))
            {

                return volumePath + documentPath;
            }
            else {

                return volumePath + File.separator + documentPath;
            }
        }
        else
        {

            return volumePath;
        }
    }


    private static String getVolumePath(final String volumeId, Context con)
    {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
        {
            return null;
        }

        try {
            StorageManager mStorageManager =
                    (StorageManager) con.getSystemService(Context.STORAGE_SERVICE);

            Class<?> storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");

            Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
            Method getUuid = storageVolumeClazz.getMethod("getUuid");
            Method getPath = storageVolumeClazz.getMethod("getPath");
            Method isPrimary = storageVolumeClazz.getMethod("isPrimary");
            Object result = getVolumeList.invoke(mStorageManager);

            final int length = Array.getLength(result);
            for (int i = 0; i < length; i++)
            {
                Object storageVolumeElement = Array.get(result, i);
                String uuid = (String) getUuid.invoke(storageVolumeElement);
                Boolean primary = (Boolean) isPrimary.invoke(storageVolumeElement);

                // primary volume?
                if (primary && PRIMARY_VOLUME_NAME.equals(volumeId))
                {
                    return (String) getPath.invoke(storageVolumeElement);
                }

                // other volumes?
                if (uuid != null)
                {
                    if (uuid.equals(volumeId))
                    {
                        return (String) getPath.invoke(storageVolumeElement);
                    }
                }
            }

            // not found.
            return null;
        }
        catch (Exception ex)
        {
            return null;
        }
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private static String getVolumeIdFromTreeUri(final Uri treeUri)
    {
        final String docId = DocumentsContract.getTreeDocumentId(treeUri);
        final String[] split = docId.split(":");

        if (split.length > 0)
        {
            return split[0];
        }
        else
        {
            return null;
        }
    }


    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private static String getDocumentPathFromTreeUri(final Uri treeUri)
    {
        final String docId = DocumentsContract.getTreeDocumentId(treeUri);
        final String[] split = docId.split(":");
        if ((split.length >= 2) && (split[1] != null))
        {
            return split[1];
        }
        else
        {
            return File.separator;
        }
    }


}

所以基本上onActivityResult我正在检查所选目录路径的treeuri是否等于我所需的路径。

这是所选目录content://com.android.externalstorage.documents/tree/primary%3Atreeuri

这是从上述treeuri/storage/sdcard0返回的路径

预期返回的路径是/storage/sdcard1

因此,即使选择了正确的目录,也会返回错误的路径。

谁能帮我找到treeuri的确切路径,或者谁能帮我检查treeuri是属于内部存储还是外部存储(SD卡)。

【问题讨论】:

    标签: java android file uri storage-access-framework


    【解决方案1】:

    我想检查用户选择的目录是否属于特定存储(内部或外部存储)的根文件夹。

    欢迎您在DocumentFile 上使用getParentFile(),看看它在文档树顶部返回什么。他们没有准确记录这里发生的事情,但它应该返回 null 或抛出某种异常。然后,您可以使用它来确定返回的文档树是否恰好是某个东西的根。

    但是,“某事”不要求是 external storageremovable storage。用户可以从 Google Drive、Windows 文件服务器或任意数量的其他数据源中选择文档树。不要求您能够识别数据源的来源。

    这是我的 FileUtil 类

    该类中的大部分代码都做出了无效的假设。其余使用反射,很有可能the next version of Android will ban access to hidden APIs using reflection

    谁能帮我找到treeuri的确切路径

    没有“treeuri 的确切路径”。

    谁能帮我检查一下treeuri是属于内部存储还是外部存储(SD卡)

    一般来说这是不可能的。

    【讨论】:

    • 您的答案总是非常出色,每一个动作都有适当的解释。但就我而言,我根本无法接受任何Uri 并保持原样。我需要这个Uri 来使用存储访问框架访问目录。如果用户选择了错误的路径并且我没有通知他,那么他会认为该应用程序无法正常运行并且没有按照应有的方式处理文件,因为权限会出现问题。我可以使用任何最近的工作吗?
    • @Rahulrr2602:“但在我的情况下,我根本无法接受任何 Uri 并保持原样”——您无法选择存储访问框架。 “如果用户选择了错误的路径”——这是你的应用程序设计中的一个基本问题。 不应该走错路。无论用户从 ACTION_OPEN_DOCUMENT_TREE Intent 中选择什么,您的应用都应该是有用的。
    • 非常感谢您的详细解释。
    【解决方案2】:

    我想检查用户选择的目录是否属于特定存储的根文件夹

    这很简单。如果内容方案以%3A 结束,那么它就是。

    所以请检查data.getData().toString()

    【讨论】:

    • 感谢您的回答。我如何知道treeuri 是内部存储还是外部存储。
    • %3A方法也会通过各种设备保持不变吗?
    • Tree uris 永远不会用于内部存储。仅适用于外部和可拆卸。那些用于外部的包含 ''/primary%3A"。
    • 如果用户选择了Internal Storage(DCIM、Download等文件夹存放的地方)怎么办?
    • 如前所述:无法选择内部存储。 DCIM 和下载文件夹等位于外部存储上。在getExternalStorageDirectory() 指示的路径上。查看函数名称 ;-)。
    猜你喜欢
    • 2011-12-31
    • 2018-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多