为什么有些 ContextCompat.getExternalFilesDirs 无法访问?

Why are some ContextCompat.getExternalFilesDirs not accessible?

ContextCompat.getExternalFilesDirs(context, null) 说:

Returns absolute paths to application-specific directories on all external storage devices where the application can place persistent files it owns.

例如华为荣耀 运行 Android 5.1.1 returns 以下来自该方法:

/storage/emulated/0/Android/data/my.package.name/files
/storage/sdcard1/Android/data/my.package.name/files

第二个目录是可移动的sd卡。但是,如果我尝试读取或写入该目录,则会出现异常:android.system.ErrnoException: open failed: EACCES (Permission denied)

该应用确实有 WRITE_EXTERNAL_STORAGE。这在 Samsung Galaxy Note 4 运行 Android 4.4.4 上工作得很好。这与 Android 6.0 的可选权限无关,因为这是在 5.1.1 上显示的问题。

API 说 the application can place persistent files it owns 但事实并非如此。

我也听说过其他设备的报告,包括更现代的三星设备。这仅仅是 OEM 没有正确实现这一点,还是我在 Android 的复杂存储框架中遗漏了什么?

下面是一些代码,将在此设备和某些设备上演示这一点。

File removable = ContextCompat.getExternalFilesDirs(context, null)[1];
if (removable.exists() && removable.canRead() && removable.canWrite()) {
    File test = new File(removable, "test");
    test.createNewFile(); // Throws the exception mentioned above
}

在该目录中创建、移动 mkdir 文件的任何尝试均失败。

嗯,我把你的代码包装在这个 activity:

package com.commonsware.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    File removable = ContextCompat.getExternalFilesDirs(this, null)[1];
    if (removable.exists() && removable.canRead() && removable.canWrite()) {
      File test = new File(removable, "test");
      try {
        test.createNewFile(); // Throws the exception mentioned above
      }
      catch (IOException e) {
        Log.e(getClass().getSimpleName(), "Exception creating file", e);
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
      }
    }
  }
}

它在华为荣耀 5X 上运行良好,运行 Android 6.0.1:

$ adb shell ls -al /storage/1A30-3598/Android/data/com.commonsware.myapplication/files
-rwxrwx--x u0_a29   sdcard_rw        0 2017-05-03 18:02 test

因此,我猜测这是设备特定的不兼容性。

出于多种原因,我想询问@CommonsWare 如何在没有 ArrayIndexOutOfBoundsException 的情况下将代码获取到 运行:length=1; index=1 错误 [0] 需要设置为 [0] 我们已经测试这个概念一段时间了,以编写一个方法让用户 select 内部或外部存储 有人可以解释这是如何工作的或为什么它对我们不起作用 上面的答案需要这样格式化

        File removable = ContextCompat.getExternalFilesDirs(this,null)[0];
    if (removable.exists() && removable.canRead() && removable.canWrite()) {

        THE_PATH = String.valueOf(removable);
        THE_PATH = THE_PATH + "/Documents/";

    }else {
        Toast.makeText(getApplicationContext(),"NO SD CARD", 
    Toast.LENGTH_LONG).show();

    }