【问题标题】:Unable to write to external storage; Access is denied无法写入外部存储;访问被拒绝
【发布时间】:2015-12-20 15:50:30
【问题描述】:

我有一个类,它存储第一次启动应用程序时从 Facebook 下载的图像。我所做的是我会使用一个类来创建一个文件夹(如果它以前不存在的话)并将所有图像存储在那里。

重要提示我已经在不同 API 的多个设备上取得了成功(均低于 23)。文件已成功写入和检索。最近我有一部使用 6.0 (API 23) 的新手机,不知何故,将文件写入存储系统的代码不再有效。我无法再在 sdcard 中创建文件夹,这会导致错误。

作为附加信息,该手机是已植根的 nexus 5X,而不是外部 SD 卡。该应用程序在 API 23 上运行,包括存储在内的危险权限在应用程序可用之前就已得到正确授权。

使用经过验证的 getExternalStorageDirectory 方法,该方法返回 emulated/0/。 Environment.MEDIA_MOUNTED 表示已授予对存储的访问权限。 问题是当我尝试创建一个文件夹时它告诉我我不能这样做。

.canwrite 表示我尝试创建的 mkdirs 目录不可访问

我的清单供您参考:

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

我写入外部存储的方法:

public static String storeImage(Bitmap bitmap, String filename) {
    String stored = null;
    String folder_main = "Samepage";
    String root = Environment.getExternalStorageDirectory().toString();
    String state = Environment.getExternalStorageState();
    Log.i(TAG,"Storage state is " + state);
    File folder = new File(root + "/Samepage");
    Log.i(TAG, folder.toString());

    if (!Environment.MEDIA_MOUNTED.equals(state)) {
        Log.e(TAG,"Storage is not mounted!");
    }

    if (folder.canWrite()) {
        Log.i(TAG, "External storage is accessible");

        if (!folder.exists()) {
            folder.mkdirs();

        }
    } else 
        Log.e(TAG, "Default storage is not accessible");


    File sdcard = Environment.getExternalStorageDirectory();
    if (folder.exists()) {
        File file = new File(root, filename + ".png");
        if (file.exists())
            file.delete();

        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
            out.flush();
            out.close();
            stored = "success";
            Log.i(TAG, "User image created successfully");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    return stored;
}

【问题讨论】:

  • 使用getExternalCacheDir()。这样就不会污染sdcard的root,可以去掉写权限。
  • 尝试 context.getExternalFilesDirs() 代替
  • “包括存储在内的危险权限已得到适当授权”——您可能希望仔细检查这一点。 “当我尝试创建一个文件夹时,它告诉我我不能这样做”——您可能希望发布整个堆栈跟踪。
  • 你是连接根和“/xxx”的字符串,这可能导致两个连续的正斜杠。你能确定你的连接路径是正确的吗?
  • 同意@LeonidUsov - 你正在连接root + "/Samepage"。处理路径字符串时的一条黄金法则是检查末尾是否已经存在路径分隔符 - 如果没有,则添加一个。如果您按照该原则工作,则始终可以确保 IS 在末尾有一个路径分隔符,并且在连接时,您永远不需要将分隔符添加到目录或文件名。

标签: android storage external


【解决方案1】:

在 API 23+ 上,我建议在任何外部存储操作之前运行此函数:    

private static final int REQUESTCODE_STORAGE_PERMISSION = 999999999;

private static boolean storagePermitted(Activity activity) {

    Boolean readPermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
    Boolean writePermission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;

    if (readPermission && writePermission) {
        return true;
    }

    ActivityCompat.requestPermissions(activity, new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }, REQUESTCODE_STORAGE_PERMISSION);
    return false;
}

此方法请求读取和写入外部存储的权限,如果您应该执行该操作,则返回 true。自 API 23 起,外部存储权限已默认禁用。

进一步阅读:developer.android.com/training/permissions/requesting.html

【讨论】:

  • REQUESTCODE_STORAGE_PERMISSION 是什么,无法解决。
  • REQUESTCODE_STORAGE_PERMISSION 是您定义用作标记的整数。当请求权限返回并调用onRequestPermissionsResult 时,您可以验证它是否是您请求的权限以及是否被授予。
猜你喜欢
  • 2018-07-05
  • 2020-10-31
  • 2020-05-05
  • 2013-08-19
  • 2012-08-07
  • 2011-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多