【问题标题】:Can't create a directory in external sd card (Lollipop)无法在外部 sd 卡(棒棒糖)中创建目录
【发布时间】:2016-08-11 23:40:15
【问题描述】:

我对内部存储没有问题,但我想在外部 SD 卡上创建一个目录,使用 KitKat 之前的版本,File.mkdirs() 有效。

我的代码中有一部分:

//external sd card
DocumentFile.fromFile(new File("/storage/sdcard1/")).exists(); //returns true
DocumentFile.fromFile(new File("/storage/sdcard1/")).canRead(); //returns true
DocumentFile.fromFile(new File("/storage/sdcard1/")).canWrite(); //returns true
DocumentFile.fromFile(new File("/storage/sdcard1/test")).exists(); //returns false
DocumentFile.fromFile(new File("/storage/sdcard1/")).createDirectory("test"); //returns null

//internal storage
DocumentFile.fromFile(new File("/storage/emulated/0/")).exists(); //returns true
DocumentFile.fromFile(new File("/storage/emulated/0/test")).exists(); //returns false
DocumentFile.fromFile(new File("/storage/emulated/0/")).createDirectory("test"); //it works
DocumentFile.fromFile(new File("/storage/emulated/0/test")).exists(); //returns true
DocumentFile.fromFile(new File("/storage/emulated/0/test")).createFile("text", "file.txt"); //it works

//external sd card
(new File("/storage/sdcard1/test2/subfolder")).exists(); //returns false
(new File("/storage/sdcard1/test2/subfolder")).mkdirs(); //returns false

//internal storage
(new File("/storage/emulated/0/test2/subfolder")).exists(); //returns false
(new File("/storage/emulated/0/test2/subfolder")).mkdirs(); //returns true

在 AndroidManifest.xml 中:

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

使用 BQ Aquaris e4、Android Lollipop 5.0 和 1GB micro SD 卡进行测试。

更新:这就是我获取卷列表的方式:

private static ArrayList<StorageInfo> listAvaliableStorage(Context context) {
        ArrayList<StorageInfo> storagges = new ArrayList<>();
        StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
        try {
            Class<?>[] paramClasses = {};
            Method getVolumeList = StorageManager.class.getMethod("getVolumeList", paramClasses);
            getVolumeList.setAccessible(true);
            Object[] params = {};
            Object[] invokes = (Object[]) getVolumeList.invoke(storageManager, params);
            if (invokes != null) {
                StorageInfo info;
                for (Object obj : invokes) {
                    Method getPath = obj.getClass().getMethod("getPath");
                    String path = (String) getPath.invoke(obj);
                    info = new StorageInfo(path);
                    File file = new File(info.getPath());
                    if ((file.exists()) && (file.isDirectory())
                        //&& (file.canWrite())
                            ) {
                        info.setTotalStorage(file.getTotalSpace());
                        info.setFreeStorage(file.getUsableSpace());
                        Method isRemovable = obj.getClass().getMethod("isRemovable");
                        String state;
                        try {
                            Method getVolumeState = StorageManager.class.getMethod("getVolumeState", String.class);
                            state = (String) getVolumeState.invoke(storageManager, info.getPath());
                            info.setState(state);
                            info.setRemovable((Boolean) isRemovable.invoke(obj));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                        storagges.add(info);
                    }
                }
            }
        } catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        storagges.trimToSize();

        return storagges;
    }

硬编码路径仅适用于本示例

更新 2: 我已经使用文件资源管理器在 SD 卡中创建了目录:“test”。当我执行这段代码时:

File file = new File("/storage/sdcard1/test/", "file.txt");
fileOutput = new FileOutputStream(file);

第二行抛出FileNotFoundException: /storage/sdcard1/test/file.txt: open failed: EACCES (Permission denied)

我做错了什么?

【问题讨论】:

  • Logcat有返回错误信息吗?
  • 您也可以发布您遇到的错误吗?另外,尝试使用 Environment.getExternalStorageDirectory().getPath() 而不是直接指向。检查这个 - >stackoverflow.com/questions/32055815/…
  • 无错误,无异常。 Environment.getExternalStorageDirectory.getPath() 返回“/storage/emulated/0/”,这不是外部sdcard

标签: android android-5.0-lollipop android-sdcard


【解决方案1】:

这是由于 Android Lollipop 的设计。 Environment.getExternalStorageDirectory() 将只返回模拟外部存储的路径。 Android 不会公开任何为您提供 sdcard 路径的 API。

此外,在 Lollipop 中,应用程序无法写入 sdcard 中自己目录之外的位置,除非通过存储访问框架获得用户权限。

试试context.getExternalFilesDirs()。这为您提供了应用程序可以写入数据的路径列表。其中一个将在 sdcard 中,类似于 /storage/sdcardname/Android/data/yourAppName/files

【讨论】:

  • getExternalFilesDirs() 返回“/storage/emulated/0/Android/data/packagename/files”,但这不是外部 sdcard。用Storage Access Framework解决了,这里有个很好的解释stackoverflow.com/questions/26744842/…
  • 您确定您使用的是 getExternalFilesDirs 而不是 getExternalFilesDir? Dir 将仅返回模拟路径。 Dirs 将返回模拟路径和 sdcard 路径。
  • 任何解决方案? @cgr
  • 是的@DeepDave,使用存储访问框架,看到这个答案stackoverflow.com/questions/26744842/…
【解决方案2】:

您必须明确定义位置,这是我创建的一个简短脚本,用于在该文件夹中创建一个文件夹和一个文件夹,希望对您有所帮助

    import java.io.File;
    import android.app.Activity;
    import android.content.Context;
    import android.os.Bundle;
    import android.os.Environment;
    import android.widget.Toast;

public class DirectoryPicker extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.chooser_list);//your xml layout file name
}
@Override
public void onStart() {
    super.onStart();
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) { // **Check that we have access to create the folder(s)**
        File Root = Environment.getExternalStorageDirectory(); //**Get the path and hold it**
//**Alternativly you can select a certain directory with**
//File Root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File folder = new File(Root.getAbsolutePath() + "/main_folder_to_add/second_folder/");//**This puts everything together CORRECTLY**
        folder.mkdirs();//**Makes the directory folders, make sure to use mkdirs not mkdir**
        if (!folder.exists()) {
            folder.mkdirs();
        }
        Context context = getApplicationContext();//**Prove we were successful**
        String msg = folder.toString();
        Toast toast = Toast.makeText(context, msg, Toast.LENGTH_LONG);
        toast.show();
        return;
    }
}
public void onBackPressed() {

finish();
}
}

【讨论】:

  • Environment.getExternalStorageDirectory.getPath() 返回“/storage/emulated/0/”,这不是外部sdcard
  • 正确这就是为什么我没有在上面的代码中使用它,首先我得到 Environment.getExternalStorageDirectory() 然后将字符串与 File folder = new File(Root.getAbsolutePath() 放在一起,不是 getPath,我在 api 4.1 和 6 上对其进行了测试,它工作并制作了用户可以轻松找到的文件夹,而我在这里看到的所有其他方法都不起作用(至少对我来说)
猜你喜欢
  • 2015-06-21
  • 1970-01-01
  • 2017-07-28
  • 2014-12-15
  • 2015-09-12
  • 2015-08-25
  • 2021-03-23
  • 2015-08-12
  • 1970-01-01
相关资源
最近更新 更多