安卓:在外部存储上使用mkdirs()/mkdir()返回false

47

我为此而疯狂:

Log.d("STATE", Environment.getExternalStorageState());
File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "work_data");
Log.d("PATH", f.getAbsolutePath());
if (!f.exists()) {
    Log.d("MAKE DIR", f.mkdirs() + "");
}

输出日志看起来像这样:

STATE     mounted
PATH      /mnt/sdcard/DCIM/work_data
MAKE DIR  false

我确保添加了正确的权限:

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

但我不知道为什么它不能创建文件夹。我也逐步使用了 mkdir() 但结果仍然相同。请帮助我。我已经Google了很多并且至少花了两天时间在这件事上。感谢您的帮助!

编辑:

对不起大家!我在<application>标签中添加了<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>,这是我的错误!但是非常感谢大家的回复。


你的问题让我解决了使用mkdirs()时遇到的问题(我缺少WRITE_EXTERNAL_STORAGE授权)。由于没有抛出“权限被拒绝”异常,所以原因并不明显... - Sébastien
是的,我也认同你的想法。安卓过于复杂化了创建文件夹和文件这样简单的任务,真是疯狂。 - Paul McCarthy
16个回答

64

我也遇到了同样的问题,我确定我已经把权限标签放在了正确的位置,但是“mkdirs”仍然没有起作用,我的系统是Android 6.0。我已经解决了这个问题,你可以按照以下步骤检查:

  1. 确保您已经将权限标签放置在正确的位置。
  2. 在手机上打开“设置/应用程序”,检查您的应用程序权限(我发现在我的清单声明中的权限在此处找不到),打开权限开关(默认情况下是关闭的,这导致“mkdirs”失败)。

输入图像描述


9
在 Android 6.0 中,当您使用某些权限时,需要请求这些权限。您可以使用函数“ActivityCompat.requestPermissions”来发起请求。更多信息请参见此处 - Chris
1
在我的情况下,我在清单中请求了权限,但是不知何故它在应用程序权限中被禁用了。你救了我的命,我爱你!❤❤❤ - claudevandort
1
出于某种原因,我只需要将此权限关闭再重新打开,它就可以正常工作了。 - Randy

34

我曾经遇到过同样的问题,寻找答案已经一周了。我认为我找到了答案,而且它非常简单,你需要将uses-permission声明放在正确的位置...

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.company.name" 
    android:versionCode="1"
    android:versionName="0.2">

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

当我将它放在<application></application>部分内时,它没有起作用。


在我的情况下,这是正确的答案。请投赞成票。 - Pham Hung
1
对我没用。 - Johann

18

仅适用于目标SDK版本为29或更高版本。

在API级别29中,Environment.getExternalStorageDirectory()已被弃用。

要获得相同的功能,请使用此行

File mediaStorageDir = context.getExternalFilesDir(null);

如果您已经检查了所有可能的错误,请尝试此修复方法。
已在此处回答 - https://dev59.com/SJffa4cB1Zd3GeqP8HVn#61480077

2
真是感谢你!不确定我为什么会错过这个,或者为什么Android Studio没有强制警告我它已经被弃用了。看起来删除它似乎是一件大事。 - KisnardOnline
1
对于targetSdkVersion 29,可能会有一些差异。getExternalFilesDir(null)是应用程序的目录,它位于.../Android/data/下,带有应用程序包名称。如果某人的旧应用程序在其他地方创建了一些目录,例如在根目录中。这个答案无法涵盖这个问题,因为它们是两个不同的目录。一个临时解决方案应该是:developer.android.com/training/data-storage/… <application android:requestLegacyExternalStorage="true" ... > - Fisher
这个也解决了我的问题,我正在使用的targetSdkVersion大于29。 - Kalyan Pradhan
getExternalFilesDir只会返回应用程序在外部存储上自己的私有数据访问权限。这些文件/文件夹对其他应用程序不可访问。 - Johann

16

我知道这是一个旧帖子,但也许我的答案可以帮助某些人。

在处理这个问题几天后,我意识到当手机连接到电脑时(在开发期间几乎总是如此),SD卡不可用。因此,任何尝试在其上创建目录或文件都会失败。 为了让它变得“容易些”,在测试电话下,它似乎表现不同。

我知道这听起来可能是一个很愚蠢的问题,但它浪费了大量时间,也许其他人能够节省一些时间。


1
可能在某些设备上,但并非所有设备上。 - Hamidreza Sadegh
那么如何在手机连接的情况下测试mkdir()函数呢? - Khay Leng

13

在OnCreate()中添加这行代码。

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

2
我在Manifest文件中有正确的权限设置,在Android 7.1上可以正常工作,但在Android 9.0上尝试时无法正常工作,使用requestPermission解决了问题,谢谢! - Sam
2
这解决了我在API 26+上的问题。 - alex_z

10

也许回答有点晚了,但如果你已经允许了R/W权限(包括运行时权限),但仍然无法工作,请在你的AndroidManifest.xml中添加以下提到的行。

<application
........
........
android:requestLegacyExternalStorage="true">

注意:如果您的目标是 Android 10+,则必须执行此操作。


6

如果文件夹已经存在,mkdirs() 函数只会返回 false,只有在成功创建了新的目录时才会返回 true。所以我猜测这个目录已经存在了。


6
不,它没有。我在“if (!f.exists()) {”这一行进行了检查。 - MHM

4
<application
        .....
        android:requestLegacyExternalStorage="true">

工作良好。


2
尽管这段代码可能解决问题,但一个好的答案也应该解释代码做了什么以及它如何帮助解决问题。 - BDL
1
不行,对我没用。 - Johann

3

我曾经遇到同样的问题,现在和大家分享我的解决方案。 根据 Android 的要求, 从 Android 4.4 开始,在应用程序的私有目录中读取或写入文件不需要 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 权限。

因此,你可以通过添加 maxSdkVersion 属性来声明仅在较低版本的 Android 上请求权限:

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

但是maxSdkVersion是问题所在,我只是将其删除后就可以正常工作了。

2

请将此放置

Log.d("MAKE DIR", f.mkdir() + "");

替代

Log.d("MAKE DIR", f.mkdirs() + "");

或者尝试这个。
String s=Environment.getExternalStorageDirectory().toString()+"/";
File f = new File(s+"DCIM/work_data");

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