You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Marshmallow设备SD卡无法保存数据至Android文件夹外求助

解决安卓6.0设备上SD卡Android文件夹外写入失败的问题

首先咱们得先理清楚你遇到的核心限制:从Android 4.4(KitKat)开始,第三方应用默认只能访问自身在SD卡上的私有目录(就是你现在用的/storage/4130-1912/Android/data/com.enable/files,要写入到Android文件夹之外的目录,得满足几个前提条件,我给你一步步拆解:

1. 先搞定必要的权限申请

安卓6.0(Marshmallow)开始要求动态申请存储权限,你得先在Manifest里声明权限:

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

然后在代码里动态申请,确保用户授权后再进行写入操作:

// 检查权限是否已授权
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
    // 申请权限
    ActivityCompat.requestPermissions(activity,
            new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
            1001); // 自定义请求码
}

2. 优先写入系统公共目录(避开沙箱限制)

即便拿到了存储权限,你也不能随意在SD卡根目录创建自定义文件夹——这是安卓的沙箱规则限制。你只能写入系统预设的公共目录,比如Documents、Pictures、Downloads这些。举个例子,获取SD卡的Documents目录并创建子文件夹:

File[] externalDirs = ContextCompat.getExternalFilesDirs(context, null);
if (externalDirs.length > 1 && externalDirs[1] != null) {
    // 从私有目录路径中提取SD卡根路径
    String sdCardRoot = externalDirs[1].getAbsolutePath().split("/Android/")[0];
    // 目标目录:SD卡Documents下的MyAppData文件夹
    File targetDir = new File(sdCardRoot + "/Documents/MyAppData");
    if (!targetDir.exists()) {
        boolean isCreated = targetDir.mkdirs();
        if (isCreated) {
            // 目录创建成功,现在可以在这里写入文件了
            Log.d("SDCard", "目录创建成功:" + targetDir.getAbsolutePath());
        } else {
            Log.e("SDCard", "目录创建失败,检查权限或SD卡状态");
        }
    }
}

3. 必须写入自定义目录?用存储访问框架(SAF)

如果你的需求一定要在Android文件夹外创建完全自定义的目录(比如/storage/4130-1912/MyCustomFolder),那只能通过SAF让用户手动授权该目录的读写权限,步骤如下:

  1. 启动SAF的目录选择器,让用户选要授权的目录:
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
startActivityForResult(intent, 1002); // 自定义请求码
  1. onActivityResult中处理授权结果,持久化权限并操作目录:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1002 && resultCode == RESULT_OK) {
        Uri treeUri = data.getData();
        // 持久化权限,确保重启App后依然有效
        getContentResolver().takePersistableUriPermission(treeUri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // 使用DocumentFile操作目录和文件
        DocumentFile rootDir = DocumentFile.fromTreeUri(this, treeUri);
        DocumentFile customDir = rootDir.createDirectory("MyCustomFolder");
        // 创建测试文件并写入内容
        DocumentFile newFile = customDir.createFile("text/plain", "test.txt");
        try (OutputStream os = getContentResolver().openOutputStream(newFile.getUri())) {
            os.write("测试SD卡自定义目录写入".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

对你现有代码的补充说明

你当前的代码是正确获取SD卡私有目录的方式,但要注意:

  • paths[1]不为空时,它就是SD卡上的App私有目录,无需额外权限就能读写
  • 只要想访问Android文件夹之外的区域,就必须走上面的权限申请或SAF流程

最后提醒:在安卓6.0设备上,一定要确保动态权限申请成功后再尝试写入,否则会直接抛出SecurityException哦。

内容的提问来源于stack exchange,提问作者Pankaj Thapa

火山引擎 最新活动