Файл існує і є директорією IS, але listFiles () повертає значення null


78

Документація для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, і результати однакові, незалежно від того, підключений телефон до мого комп’ютера чи ні - тому я не думаю, що це пов’язано з кріпленням при підключенні.


4
Це не проблема дозволів? Чи має звичайний користувач доступ до цього каталогу?
Peterdk

1
ви пробували помістити файл у цей каталог? Мені здається, що документація насправді передбачає, що вона буде нульовою, якщо це не каталог, але вона також поверне нуль, якщо там немає фактичних Файлів
DigCamara

@DigCamara Ну, на Java, File включає каталоги - і в цій папці є каталоги.
Wilson

@Peterdk Я перейшов на / sdcard, який вказує на те саме, і, я думаю, відкритий для користувачів ..?, І отримав ті самі результати.
Wilson

1
Що File#canRead()тобі говорить? (Якщо це неправда, і я впевнений, що це так, ви отримаєте, nullколи спробуєте прочитати зміст директора)
zapl

Відповіді:


96

Для тих, хто має цю проблему, додайте це до AndroidManifest.xml:

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

Вирішена проблема: D

EDIT: Якщо це не працює, просто переконайтеся, що шлях правильний


3
+5 за цю відповідь! Цікаво, чому немає помилки, коли я не маю цього дозволу в logcat?
Мікер

22
На Marshmallow + вам потрібно також викликати наступне: ActivityCompat.requestPermissions (Activity, new String [] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
IHeartAndroid

1
IHeartAndroid: Я намагався скопіювати та вставити цей код, і він не працював, поки не зрозумів, що ви вимагаєте WRITE_EXTERNAL_STORAGE замість READ_EXTERNAL_STORAGE, як це робить відповідь.
Matt Gregory

42

Окрім інших відповідей та коментарів, я пропоную вам перевірити, чи потрібно

<application android:requestLegacyExternalStorage="true"

у вашому маніфесті. Здається, це потрібно деяким недавнім апісам.

У будь-якому випадку, коментар zapl досить короткий, але досить проникливий. Ви можете "ls -ld" каталог на пристрої (через "оболонку adb" або деякі інші оболонки). Якщо у вас є дозвіл "r" у каталозі, ви можете викликати listFiles (). В іншому випадку він повертає нуль. Зверніть увагу, що ви можете отримати доступ до файлів у нечитабельному каталозі, якщо знаєте імена файлів і маєте дозвіл "x" на каталог. Ви можете дізнатися, хто ви, за командами "whoami" та "groups".


7
Потрібно для Android 10
linquize

@tamo Сер, Ви рятуєте життя.
Кумар

@linquize Дякую.
Кумар

25

Для андроїд версії 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));

}

У мене проблема з внутрішнім сховищем
Ігор Ганапольський,

Це рішення єдине, що працювало для мене. Випробувано в Нуга 7.0
Біллійокер

13

Для тих, хто має цю проблему, ви повинні дозволити читати, додайте це до AndroidManifest.xml:

android:name="android.permission.READ_EXTERNAL_STORAGE" 

і ви також повинні надати дозвіл від

Налаштування> Програми> "Назва вашого додатка" > Дозволи> сховище


Це правильне рішення в моєму випадку. Він не вимагає зміни коду і застосовується до всіх додатків, що працюють на Lollipop, але не пристосований до нової концепції Marshmallow надання дозволів під час роботи .
GoranM

Як щодо внутрішнього зберігання?
Ігор Ганапольський

8

З документації до методу Файл 'listFiles': Повертає значення null, якщо це абстрактне ім'я шляху не позначає каталог або якщо виникає помилка вводу-виводу.

Тож, можливо, сталася помилка вводу-виводу. Перевірте дозволи в цьому каталозі, чи має користувач, що запускає програму Java, дозвіл на читання цього каталогу? Якщо ні, то є ваша відповідь. Якщо вони це роблять, можливо, каталог порожній.

До речі, ви не повинні використовувати "" для перетворення чогось у рядок, це погана практика, оскільки це повільніше, ніж String.valueOf. Я б використав StringUtils apache, щоб об’єднати цей масив у рядок, але для цього потрібно додати цей jar до шляху до вашого класу.


4

Просто додайте дозвіл у маніфесті, uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" і ваша проблема буде вирішена.


3

Відповідь @ tamo вирішив мою проблему, я склав exoplayer на ANQ і встановив:

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.


1

Моя проблема полягала в тому, що з якихось причин атрибут android: sharedUserId = "android.uid.system" не дозволяв програмі читати / sdcard / на певному пристрої.

Оскільки мені потрібно було зробити лише швидкий тест, я видалив атрибут sharedUserId, протестував і додав його назад.


0

У мене була така сама проблема в Java, але не в android, де я читаю конфігураційний файл із шляхом у лапках. Я вирішив свою проблему, просто видаливши лапки

Тож ви можете зробити це за допомогою функції String replace або надати без лапок

Рядок someString = "C: \ path"; someString = someString.replace ("\" "," ");


-1

<uses-permission .... >Додайте цей рядок у файл маніфесту в розділі android:name="android.permission.READ_EXTERNAL_STORAGE". Я думаю, це може вирішити вашу проблему.


3
Хіба це не просто повторення існуючих відповідей?
Панг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.