如何在Android中重命名文件只知道它的媒体内容Uri

Posted

技术标签:

【中文标题】如何在Android中重命名文件只知道它的媒体内容Uri【英文标题】:How to rename a file in Android knowing only its media content Uri 【发布时间】:2019-08-14 07:37:15 【问题描述】:

Android Q 中,MediaStore.Files.FileColumns.DATA 字段为 deprecated,可能为 null 或应用可能无权读取它,因此,有没有办法仅使用其媒体内容 Uri 来重命名文件的文件名部分(而不是路径)?

到目前为止,DATA 字段可用于从已知 Uri 中找到文件的真实路径,但由于它已被弃用,因此我们的想法是甚至不尝试查找或解析真实文件路径,并且仅使用它的内容 Uri。

考虑到 Uri 将采用标准媒体内容格式(不是 SAF 格式):content://media/external/images/media/123

目的是重命名 Uri 指向的文件的名称。

我知道我可以更新 MediaStore 的 TITLE 和 DISPLAY_NAME 字段,但这不会更改文件名,如果用户决定将文件移到设备外,那么此文件仍将具有旧文件名。

【问题讨论】:

我猜这是不可能的。对于MediaStore 和存储访问框架,文件名是一个实现细节,而不是开发人员看到或操作的东西。用户碰巧看到文件名的事实意味着MediaStore 和存储访问框架抽象有点泄漏。 DocumentFile.renameTo(String) 尝试过,在 sdcard 中的文件上。它在模拟器上工作,但实现似乎不稳定,因为尽管文件被重命名,但它返回“false”(或者它可能被复制并以不同的名称重新创建? - 无法判断,但文档指出可能是这种情况)。 您是如何创建 DocumentFile 的?如果我错了,请纠正我,但据我所知,DocumentFile 只能从原始文件或使用 fromSingleUri 创建,它需要通过 SAF 创建的 Uri,而不是来自媒体内容 Uri,例如:内容: //媒体/外部/图像/媒体/123 【参考方案1】:

更新

嗨,首先为我之前的业余回答道歉。但是,我想不出任何直接的方法来完成这个要求。但是,我认为可能有一种解决方法,总比没有好。

我们可以仅使用 Uri 重命名文件的唯一方法是通过 SAF 使用 DocumentsContract。我们现在掌握的是 MediaStore Uri,我们需要获取该文件的等效 Document Uri。为此,我们可以使用MediaStore.getDocumentUri( context , mediaUri )。问题是,我们需要在获取 Document Uri 之前通过调用此方法获得权限。我们可以获取挂载存储卷的 DocumentTree Uri 的持久化 Uri 权限(或者单独的任何特定目录,其中包含我们要修改的媒体文件)。通过这样做,现在我们将拥有媒体文件的 Documents Uri 的权限,我们可以使用DocumentsContract.renameDocument 重命名该文件。

步骤 1-4 将是一次性的(直到手动撤销)

    在 Manifest 中声明 android.permission.READ_MEDIA_IMAGES 权限。 向用户请求 READ_MEDIA_IMAGES 权限。

    请求拥有媒体文件的存储卷的 DocumentTree 的 Uri 权限。

        StorageManager manager = getSystemService(StorageManager.class);
    
        StorageVolume primaryStorageVolume = manager.getPrimaryStorageVolume();
    
        startActivityForResult(primaryStorageVolume.createOpenDocumentTreeIntent(), STORAGE_PERMISSION_REQ_CODE);
    

但是,请注意,根据 Android 的文档,用户可以选择我们要求的位置以外的位置。

    onActivityResult 获取结果 Uri 的持久权限

        if (resultCode == RESULT_OK) 
            getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        
    

    现在获取媒体文件的 Documents Uri 并重命名。

    Uri docUri = MediaStore.getDocumentUri( context , mediaUri );
    DocumentsContract.renameDocument(contentResolver, docUri, "newFileName.ext");
    

所以基本上我们必须两次询问用户权限,一次用于存储 访问和第二个用于 Uri 访问。因为我们会得到一个持久化的 Uri 许可,此提示将是一次性的,并且会持续 直到我们撤销它。我们可以使用它的 Document Uri 访问所有文件 无需用户选择。


上一个答案

我认为我们可以利用 DocumentsContract。但为此,您应该使用Intent.ACTION_OPEN_DOCUMENT 而不是Intent.GET_CONTENT 请求文件。获得 URI 后,您可以使用 DocumentsContract.renameDocument 重命名该文件

DocumentsContract.renameDocument(contentResolver, uri, "newFileName.ext");

但是,提供 URI 的 DocumentProvider 应该支持重命名功能。例如,如果我从Recents 中选择一个文件,则不支持重命名。但是,如果我选择与其他提供程序相同的文件,比如默认文件管理器,将支持重命名操作。您可以通过检查是否在结果意图中设置了标志 DocumentsContract.Document.FLAG_SUPPORTS_RENAME 来验证这一点。

【讨论】:

感谢您的回答。然而,这不是我们正在寻求的解决方案,因为这意味着除了请求 READ_MEDIA_IMAGES 权限之外,我们还必须再次请求存储位置。尽管如此,您的代码可能对寻求不同工作流程的其他开发人员有用,因此我们对答案给予 +1,但我们不能接受它作为解决方案。谢谢。 另外,请查看Roles 是否有可能。 developer.android.com/preview/privacy/… 我们查看了角色,但这些角色不可共享,这意味着只有一个应用程序可以成为特定角色的所有者,因此仅将所有广泛权限授予 1 个应用程序,其余的保留的应用程序,因为他们可以处理新的约束。对于开发人员来说,Android Q 似乎将是一个困难的版本。无论如何,谢谢你的提示。 android.permission.READ_MEDIA_IMAGES 不存在! 但是 android.permission.READ_EXTERNAL_STORAGE 是的。

以上是关于如何在Android中重命名文件只知道它的媒体内容Uri的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 设备管理器中重命名设备

在android中重命名包名

在android studio中重命名包名称后启动错误,运行时错误

Android Studio 4.2 开始在发布版本中重命名 APK 内的资源

在 Visual Studio 中重命名某些内容时,如何查看“无法解决的冲突”是啥?

在linux中重命名文件时包含文件夹名称