在/sdcard中创建目录失败

59

我一直在尝试以编程方式在/sdcard中创建一个目录,但是不起作用。下面的代码总是输出directory not created.

boolean success = (new File("/sdcard/map")).mkdir(); 
if (!success) {
    Log.i("directory not created", "directory not created");
} else {
    Log.i("directory created", "directory created");
}
13个回答

152

这里有三件事情需要考虑:

  1. 不要假设SD卡已经挂载到/sdcard(可能在默认情况下是正确的,但最好不要硬编码)。您可以通过查询系统来获取SD卡的位置:

    Environment.getExternalStorageDirectory();
    
    你需要在 AndroidManifest.xml 文件中添加使用权限条目,告诉 Android 应用程序需要写入外部存储器。
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    
    如果该目录已经存在,那么mkdir会返回false。因此请检查目录是否存在,如果不存在则尝试创建它。 在您的组件中,请使用类似以下的代码:
    File folder = new File(Environment.getExternalStorageDirectory() + "/map");
    boolean success = true;
    if (!folder.exists()) {
        success = folder.mkdir();
    }
    if (success) {
        // Do something on success
    } else {
        // Do something else on failure 
    }
    

8
在Froyo版本之前,SD卡被挂载在/sdcard路径下。从Froyo版本开始,SD卡被挂载在/mnt/sdcard路径下,并创建了一个软链接到/sdcard路径,以便应用程序仍能正确运行,尽管挂载点发生了变化。 - Gopinath
2
因为某些原因,这段代码在我的myTouch手机上无法正常工作...嗯,.mkdir()方法总是返回false。 - JPM
3
我认为你应该检查权限,以及磁盘是否挂载到了计算机文件系统上。 - Gopinath
在 XML 文件中,uses-permission 块应该放在哪个位置? - Tomáš Zato
它应该是AndroidManifest中应用程序元素的兄弟节点。 - Arthur Thompson
1
我曾遇到类似问题,发现如果我的手机通过USB连接到电脑上,就无法创建目录。当我断开手机连接后再次运行应用程序时,它成功地创建了文件夹和文件。 - Kamran Bigdely

28

我在将我的安卓手机更新到6.0(API级别23)后遇到了同样的问题。以下解决方案对我有效,希望它也能帮到你。

请检查你的安卓版本。如果它是>= 6.0(API级别23),你不仅需要包含

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

在你的AndroidManifest.xml中,还需要像以下代码一样在调用mkdir()之前请求权限。这些代码我是从https://developer.android.com/training/permissions/requesting.html复制过来的。
public static final int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
= 1; public int mkFolder(String folderName){ // make a folder under Environment.DIRECTORY_DCIM
    String state = Environment.getExternalStorageState();
    if (!Environment.MEDIA_MOUNTED.equals(state)){
        Log.d("myAppName", "Error: external storage is unavailable");
        return 0;
    }
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        Log.d("myAppName", "Error: external storage is read only.");
        return 0;
    }
    Log.d("myAppName", "External storage is not read only or unavailable");

    if (ContextCompat.checkSelfPermission(this, // request permission when it is not granted. 
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        Log.d("myAppName", "permission:WRITE_EXTERNAL_STORAGE: NOT granted!");
        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

            // Show an expanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.

        } else {

            // No explanation needed, we can request the permission.

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE);

            // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    }
    File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),folderName);
    int result = 0;
    if (folder.exists()) {
        Log.d("myAppName","folder exist:"+folder.toString());
        result = 2; // folder exist
    }else{
        try {
            if (folder.mkdir()) {
                Log.d("myAppName", "folder created:" + folder.toString());
                result = 1; // folder created
            } else {
                Log.d("myAppName", "creat folder fails:" + folder.toString());
                result = 0; // creat folder fails
            }
        }catch (Exception ecp){
            ecp.printStackTrace();
        }
    }
    return result; }

@Override public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    } }

@BalajiSrinivasan,不是的!只适用于所谓的“危险权限”。请查看我回答底部的链接以了解他们是谁。 - anon
终于!!我一整天都在寻找这个信息,试图弄清楚为什么在指定权限后我的清单文件中还是收到了“fail readDirectory() errno=13”的消息。谢谢! - Amber
我比较迟钝,所以这篇文章对我来说不太够。这是我最终找到的一个视频,非常清晰地演示了如何请求权限 - https://www.youtube.com/watch?v=C8lUdPVSzDk - Shadoninja
嗨,这篇文章帮助了我很多,让我避免了异常情况和需要创建的文件夹。但是我仍然看不到我的文件夹和其中的文件。我想在“文档”文件夹中创建一个新文件夹,并将我的文件保存在那里。有什么建议吗?设备已重新启动... - pillesoft
嘿,Pillesoft,你的API级别是多少?在使用上述代码后,你是否看到任何要求你允许从Android写入的弹出窗口?如果看到,请点击“是”。这样你就授予权限进行写操作,然后调用mkdir()。否则,你的实现可能会出现一些错误。祝好运! - anon
显示剩余3条评论

16

访问sd卡的正确路径为

/mnt/sdcard/

但是,正如之前回答的那样,你不应该硬编码它。如果你使用Android 2.1或更高版本,请使用

getExternalFilesDir(String type) 
否则:
Environment.getExternalStorageDirectory()

请仔细阅读 https://developer.android.com/guide/topics/data/data-storage.html#filesExternal

此外,您需要使用这种方法或类似的方法。

boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();

if (Environment.MEDIA_MOUNTED.equals(state)) {
    // We can read and write the media
    mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    // We can only read the media
    mExternalStorageAvailable = true;
    mExternalStorageWriteable = false;
} else {
    // Something else is wrong. It may be one of many other states, but all we need
    //  to know is we can neither read nor write
    mExternalStorageAvailable = mExternalStorageWriteable = false;
}

然后检查您是否可以访问sd卡。如前所述,请阅读官方文档。

另一个选择是,也许您需要使用mkdirs而不是mkdir

file.mkdirs()

创建名称为此文件的末尾文件名的目录,包括创建此目录所需的完整目录路径。


2
在任何Android版本中,Environment上都没有getExternalFilesDir()方法。你可能是在想Context上的getExternalFilesDir()方法,它是在2.2版本中添加的。然而,这个方法有点问题--在应用程序升级期间,它提供的目录的内容会被删除。希望在Gingerbread版本中能够修复这个问题。 - CommonsWare
谢谢,问题已解决。我快速浏览了数据存储部分,并假设它只是像getExternalStorageDirectory()一样被访问,这也是我使用的方法。 - Maragues
正如先前提到的,我已经测试了状态。状态显示为装载,但我无法创建文件夹。 - Amit Thaper

15

重新启动您的Android设备。在我重新启动设备后,事情开始运作。


我认为我已经调试了我的应用程序,其中一个写入锁被锁定,并且从未释放。 - Uriel Frankel
使用mediaScan或sendbroadcast到Media_mount,以便使用新目录刷新媒体存储。https://dev59.com/unA75IYBdhLWcg3wbofM - shehzy

7
如果你使用的是Android 6并且编译目标>=23,发现这个问题,请注意我们现在使用运行时权限。因此,在清单中授予权限已经不再足够。

6

使用mkdirs()代替mkdir()..这对我有用 :)

File folder = new File(Environment.getExternalStorageDirectory()+"/Saved CGPA");
if(!folder.exists()){
    if(folder.mkdirs())
    Toast.makeText(this, "New Folder Created", Toast.LENGTH_SHORT).show();
}

File sdCardFile = new File(Environment.getExternalStorageDirectory()+"/Saved CGPA/cgpa.html");

3

在 Android API >= 23 中

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

替代

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

1

有许多事情需要您担心: 1. 如果您使用的是Android Marshmallow以下版本,则必须在清单文件中设置权限。 2. 如果您使用的是Android Marshmallow到Oreo版本之间的较新版本,则必须手动在应用信息中设置存储权限。如果您想在运行时设置它,可以使用以下代码。

public  boolean isStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
    if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
            == PackageManager.PERMISSION_GRANTED) {
        Log.v(TAG,"Permission is granted");
        return true;
    } else {

        Log.v(TAG,"Permission is revoked");
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        return false;
    }
}
else { //permission is automatically granted on sdk<23 upon installation
    Log.v(TAG,"Permission is granted");
    return true;
}

}


1

是的,我已经在应用程序标签中的清单文件中添加了这行代码,但仍然无法创建目录。 - sajjoo
如果您正在使用API 23运行应用程序,则首先必须向用户请求权限。 https://developer.android.com/training/permissions/requesting.html - Bishoy Fakhry
Bishoy - 这并不完全正确。只有当您的目标API为23及以上时,才必须在运行时请求权限。如果您的目标SDK较低,则即使在SDK 23+上运行时,也无需请求运行时权限。 - d.aemon

1

这个文件夹不是已经创建了吗?如果文件夹已经存在,mkdir 也会返回 false。 mkdir


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接