【问题标题】:File exists and IS directory, but listFiles() returns null文件存在且是目录,但 listFiles() 返回 null
【发布时间】:2014-01-09 22:21:44
【问题描述】:

The documentation for File.listFiles() 建议只有在调用它的文件不是目录的情况下才会返回null

我有以下:

String dir = "/storage/emulated/0";
File f = new File(dir);
Log.v("Files",f.exists()+"");
Log.v("Files",f.isDirectory()+"");
Log.v("Files",f.listFiles()+"");

日志如下:

true
true
null

由于某种原因,listFiles() 正在返回 null,即使 File 被识别为有效目录。我对 Android 文件层次结构的行为不是很熟悉,所以我猜问题出在那儿。

作为参考,我在我的 Moto X 上调试,无论手机是否插入我的电脑,结果都是一样的 - 所以我认为这与插入时的安装无关。

【问题讨论】:

  • 不是权限问题吗?普通用户是否有权访问该目录?
  • 您是否尝试将文件放入该目录?在我看来,文档实际上建议的是,如果它不是目录,它将为 null,但如果那里没有实际的文件,它也会返回 null
  • @DigCamara 好吧,在 Java 中,文件包括目录 - 并且该文件夹中有目录。
  • @Peterdk 我切换到 /sdcard,它指向同一个东西,我认为它对用户开放..?,并得到了相同的结果。
  • File#canRead() 告诉你什么? (如果这是错误的,我很确定它是错误的,当您尝试读取目录的内容时,您将收到 null

标签: java android file io file-permissions


【解决方案1】:
  1. 列表项

将此添加到您的 AndroidManifest.xml 它对我有用。

【讨论】:

    【解决方案2】:

    首先确保您请求读取外部存储的权限

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

    如果您愿意,可以使用 Dexter 库请求权限,使用 dexter 库请求权限非常容易

    这里是链接

    Dexter library

    然后在 manifest

    标签中添加以下标签
    android:requestLegacyExternalStorage="true"
    

    那么 listFiles() 函数将不会返回空数组

    【讨论】:

      【解决方案3】:

      @tamo 的回答解决了我的问题,我在 ANQ 上编译 exoplayer,并设置:

      build.gradle:

      android {
      compileSdkVersion 29
      buildToolsVersion '29.0.0'
      
      defaultConfig {
          minSdkVersion 16
          targetSdkVersion 29
      }
      

      manifest.xml:

        <application
        android:name="com.google.android.exoplayer.demo.ExoPlayerDemoApplication"
        android:label="@string/application_name"
        android:icon="@drawable/ic_launcher"
        android:largeHeap="true"
        android:allowBackup="false"
        android:requestLegacyExternalStorage="true">
      

      我查看了 android 开发网站,它已经解释了这一点: https://developer.android.com/training/data-storage/compatibility

      如果您以 API 29 或更高版本为目标,只需按照 google 的设置即可。

      【讨论】:

        【解决方案4】:

        除了其他答案和cmets,我建议你检查一下你是否需要

        <application android:requestLegacyExternalStorage="true"
        

        在您的清单中。 It seems that some recent apis need it.

        无论如何,zapl's comment 很短但很有见地。 您可以“ls -ld”设备上的目录(通过“adb shell”或其他一些 shell)。 如果您对该目录具有“r”权限,则可以调用 listFiles()。否则,它返回 null。请注意,如果您知道文件名并且对该目录具有“x”权限,则可以访问不可读目录下的文件。 你可以通过“whoami”和“groups”命令知道你是谁。

        【讨论】:

        【解决方案5】:

        对于 23 或更高版本,您需要在 onresume 方法中以编程方式授予 运行时权限,如下所示,

        public final String[] EXTERNAL_PERMS = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE
        };
        
        public final int EXTERNAL_REQUEST = 138;
        
        requestForPermission();
        
        public boolean requestForPermission() {
        
            boolean isPermissionOn = true;
            final int version = Build.VERSION.SDK_INT;
            if (version >= 23) {
                if (!canAccessExternalSd()) {
                    isPermissionOn = false;
                    requestPermissions(EXTERNAL_PERMS, EXTERNAL_REQUEST);
                }
            }
        
            return isPermissionOn;
        }
        
        public boolean canAccessExternalSd() {
            return (hasPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE));
        }
        
        private boolean hasPermission(String perm) {
            return (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this, perm));
        
        }
        

        【讨论】:

        • 内部存储有这个问题
        • 此解决方案是唯一对我有用的解决方案。在 Nougat 7.0 中测试
        【解决方案6】:

        我在 java 中遇到了同样的问题,但在 android 中没有,我正在读取带引号的路径的配置文件。我通过删除引号解决了我的问题

        所以你可以通过字符串替换功能或不加引号来实现它

        String someString= "C:\path"; someString=someString.replace("\"","");

        【讨论】:

          【解决方案7】:

          对于有此问题的人,您可以授予读取权限,请将其添加到 AndroidManifest.xml:

          android:name="android.permission.READ_EXTERNAL_STORAGE" 
          

          您还应该授予来自

          的许可

          设置 > 应用 > “您的应用名称” > 权限 > 存储

          【讨论】:

          • 这对我来说是正确的解决方案。它不需要更改代码,适用于所有在 Lollipop 上运行的应用程序,但不适用于 Marshmallow 的 granting permissions at run time 新概念。
          • 内部存储怎么样?
          【解决方案8】:

          &lt;uses-permission .... &gt; 部分的清单文件中,添加此行android:name="android.permission.READ_EXTERNAL_STORAGE"。我认为这可能会解决您的问题。

          【讨论】:

          • 这不只是对现有答案的重复吗?
          【解决方案9】:

          只需在清单uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" 中添加权限即可解决您的问题。

          【讨论】:

            【解决方案10】:

            我的问题是由于某种原因 android:sharedUserId="android.uid.system" 属性不允许应用在特定设备上读取 /sdcard/。

            因为我只需要做一个快速测试,我删除了 sharedUserId 属性,测试并添加回来。

            【讨论】:

              【解决方案11】:

              对于有此问题的人,将其添加到 AndroidManifest.xml:

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

              问题解决了:D

              编辑:如果这不起作用,请确保路径是否正确

              【讨论】:

              • 这个答案+5!我想知道为什么没有错误说我在logcat中没有这个权限?
              • 在 Marshmallow+ 上,您还需要调用以下命令:ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
              • IHeartAndroid:我试图复制并粘贴此代码,但直到我意识到您正在请求 WRITE_EXTERNAL_STORAGE 而不是 READ_EXTERNAL_STORAGE 答案时,它才起作用。
              • 如下 tamo 所述(从 Android 10 及更高版本开始),现在需要在清单中包含 android:requestLegacyExternalStorage="true" !!!
              【解决方案12】:

              来自 File 'listFiles' 方法文档:如果此抽象路径名不表示目录,或者发生 I/O 错误,则返回 null。

              所以可能发生了 I/O 错误。检查该目录的权限,运行java程序的用户是否有读取该目录的权限?如果没有,这就是你的答案。如果是这样,那么目录可能是空的。

              顺便说一句,您不应该使用 +"" 将某些内容转换为字符串,这是一种不好的做法,因为它比 String.valueOf 慢。我会使用 apache 的 StringUtils 将该数组加入一个字符串,但这需要将该 jar 添加到您的类路径中。

              【讨论】:

                猜你喜欢
                • 2021-07-07
                • 1970-01-01
                • 1970-01-01
                • 2016-09-27
                • 1970-01-01
                • 2020-01-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多