如何在 API 29 中弃用 getExternalStorageDirectory 时读取或写入文件?

Posted

技术标签:

【中文标题】如何在 API 29 中弃用 getExternalStorageDirectory 时读取或写入文件?【英文标题】:How to read or write file as getExternalStorageDirectory is deprecated in API 29? 【发布时间】:2019-11-11 03:49:14 【问题描述】:

我正在学习 android 开发,我在阅读 java 中的 getExternalStorageDirectory 时遇到了一些问题,我已阅读 https://developer.android.com/reference/android/os/Environment 但无法理解,有人可以帮助我使用 java 中的示例代码。

【问题讨论】:

【参考方案1】:

从docs可以看到:

getExternalStoragePublicDirectory(String type)

此方法在 API 级别 29 中已弃用。为了提高用户隐私,不建议直接访问共享/外部存储设备。什么时候 一个应用程序以 Build.VERSION_CODES.Q 为目标,从这里返回的路径 应用程序不再可以直接访问方法。应用程序可以继续 通过迁移到访问存储在共享/外部存储上的内容 Context#getExternalFilesDir(String) 等替代方案, MediaStore,或 Intent#ACTION_OPEN_DOCUMENT。

不向此函数传递任何参数,以将您的目录作为File 对象:

context.getExternalFilesDir();

这里的“上下文”是this.getContext();获取的对象

this是Activity的当前对象。使用时请仔细检查范围。

重要

要访问内部存储空间,AndroidManifest.xml 文件中需要 Manifest.permission.WRITE_EXTERNAL_STORAGE 和/或 Manifest.permission.READ_EXTERNAL_STORAGE

可选信息:

    通常内部存储有路径 /sdcard/ 在 Android 设备上。这不是真正的路径,而是symlink。

    这很令人困惑,但 Android 中的“外部 sdcard”实际上是指内部设备存储,而不是外部可弹出的设备外存储卡存储。 另请注意,真正的外部sdcard无法完全访问

    Activity 类扩展了 Context 类这就是我们可以从中获取上下文的原因。

【讨论】:

请注意,此方法返回的路径会在应用卸载时被删除。它不会提供与Environment.getExternalStorageDirectory() 相同的位置。【参考方案2】:

更新

从 Android 11 开始,它不允许在根目录中创建文件夹/文件,但我们仍然可以在公共目录的帮助下管理文件夹分离(它会显示已弃用的警告,但它会起作用)

fun getAbsolutePath(context: Context): File 
    return File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "YOUR_FOLDER_NAME"))

现在,用公共目录路径创建文件

val file = File(getAbsolutePath(requireContext()), "FILENAME.EXTENSION")

老年人

使用此静态方法。 目前我没有找到任何合法的方式来做到这一点。 所以,我做了这个静态方法来获取 root 或 getAbsolutePath 文件路径。

public static File getAbsoluteDir(Context ctx, String optionalPath) 
        String rootPath;
        if (optionalPath != null && !optionalPath.equals("")) 
            rootPath = ctx.getExternalFilesDir(optionalPath).getAbsolutePath();
         else 
            rootPath = ctx.getExternalFilesDir(null).getAbsolutePath();
        
        // extraPortion is extra part of file path
        String extraPortion = "Android/data/" + BuildConfig.APPLICATION_ID
                + File.separator + "files" + File.separator;
        // Remove extraPortion
        rootPath = rootPath.replace(extraPortion, "");
        return new File(rootPath);
    

【讨论】:

静态路径总是一个不好的解决方案,因为 Android 太分散了,您的制造商可能有不同的目录路径。不要使用这个 所有设备通用。你可以检查一下。【参考方案3】:

使用getExternalFilesDir()getExternalCacheDir()getExternalMediaDirs() (上下文方法)而不是Environment.getExternalStorageDirectory()

String root = mContext.getExternalFilesDir(null).getAbsolutePath();
File myDir = new File(root + "/" + mContext.getResources().getString(R.string.app_name) + "_share");
    myDir.mkdirs();

    
    

【讨论】:

以上是关于如何在 API 29 中弃用 getExternalStorageDirectory 时读取或写入文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PHPDoc 中弃用 PHP 的魔法属性?

如何在 Xcode 中弃用方法

UIAlertView 已弃用:首先在 iOS 9.0 中弃用 - UIAlertView 已弃用。将 UIAlertController 与首选样式一起使用

thumbnailImageAtTime:timeOption 已弃用:首先在 iOS 7 中弃用

Firebase 实例 ID:在 21.0.0 中弃用 getId()

iOS10 (Swift 3.0) 中弃用 UILocalNotification 接收功能