Datei existiert und IS-Verzeichnis, aber listFiles () gibt null zurück

76

Die Dokumentation fürFile.listFiles() schlägt vor, dass nullNUR für den Fall zurückgegeben wird, dass die aufrufende Datei kein Verzeichnis ist.

Ich habe folgendes:

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()+"");

Das Protokoll lautet:

true
true
null

Aus irgendeinem Grund listFiles(kehrt) zurück null, obwohl das Fileals gültiges Verzeichnis erkannt wird. Ich bin mit dem Verhalten der Android-Dateihierarchie nicht besonders vertraut, daher würde ich vermuten, dass das Problem darin liegt.

Als Referenz debugge ich auf meinem Moto X und die Ergebnisse sind die gleichen, unabhängig davon, ob das Telefon an meinen Computer angeschlossen ist oder nicht. Ich glaube also nicht, dass es mit der Montage beim Anschließen zu tun hat.

Wilson
quelle
4
Ist es nicht ein Berechtigungsproblem? Hat ein normaler Benutzer Zugriff auf dieses Verzeichnis?
Peterdk
1
Haben Sie versucht, eine Datei in dieses Verzeichnis zu stellen? Mir scheint, dass die Dokumentation tatsächlich vorschlägt, dass es null sein wird, wenn es kein Verzeichnis ist, aber es würde auch null zurückgeben, wenn keine tatsächlichen Dateien darin sind
DigCamara
@DigCamara Nun, in Java enthält File Verzeichnisse - und es gibt Verzeichnisse in diesem Ordner.
Wilson
@Peterdk Ich habe zu / sdcard gewechselt, was auf dasselbe hinweist, und ich denke, es ist offen für Benutzer ..? Und habe die gleichen Ergebnisse erzielt.
Wilson
1
Was File#canRead()sagt dir das? (Wenn das falsch ist und ich bin mir ziemlich sicher, werden Sie es bekommen, nullwenn Sie versuchen, den Inhalt des Direktors zu lesen)
zapl

Antworten:

94

Fügen Sie für diejenigen mit diesem Problem Folgendes zu AndroidManifest.xml hinzu:

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

Problem gelöst: D.

BEARBEITEN: Wenn dies nicht funktioniert, stellen Sie einfach sicher, dass der Pfad korrekt ist

BamsBamx
quelle
3
+5 für diese Antwort! Ich frage mich, warum es keinen Fehler gibt, der besagt, dass ich diese Berechtigung in logcat nicht habe.
Micer
21
Auf Marshmallow + müssen Sie auch Folgendes aufrufen: ActivityCompat.requestPermissions (Aktivität, neuer String [] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode);
IHeartAndroid
1
IHeartAndroid: Ich habe versucht, diesen Code zu kopieren und einzufügen, und es hat nicht funktioniert, bis mir klar wurde, dass Sie WRITE_EXTERNAL_STORAGE anstelle von READ_EXTERNAL_STORAGE anfordern, während die Antwort dies tut.
Matt Gregory
38

Zusätzlich zu anderen Antworten und Kommentaren würde ich vorschlagen, dass Sie prüfen, ob Sie benötigen

<application android:requestLegacyExternalStorage="true"

in deinem Manifest. Es scheint, dass einige neuere Apis es brauchen.

Wie auch immer, Zapls Kommentar ist ziemlich kurz, aber ziemlich aufschlussreich. Sie können das Verzeichnis auf dem Gerät "ls -ld" (über "adb shell" oder einige andere Shells). Wenn Sie die Berechtigung "r" für das Verzeichnis haben, können Sie listFiles () aufrufen. Andernfalls wird null zurückgegeben. Beachten Sie, dass Sie auf Dateien im unlesbaren Verzeichnis zugreifen können, wenn Sie die Dateinamen kennen und die Berechtigung "x" für das Verzeichnis haben. Sie können anhand der Befehle "whoami" und "groups" erkennen, wer Sie sind.

Tamo
quelle
5
Benötigt für Android 10
Linquize
25

Für Android Version 23 oder höher müssen Sie die Laufzeitberechtigung programmgesteuert in der folgenden Onresume-Methode erteilen.

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));

}
varotariya vajsi
quelle
Ich habe dieses Problem mit dem internen Speicher
IgorGanapolsky
Diese Lösung ist die einzige, die für mich funktioniert hat. Getestet in Nougat 7.0
Billyjoker
13

Wenn Sie mit diesem Problem Leseberechtigungen erteilen möchten, fügen Sie diese zu AndroidManifest.xml hinzu:

android:name="android.permission.READ_EXTERNAL_STORAGE" 

und Sie sollten auch die Erlaubnis von erteilen

Einstellungen> Apps> "Ihr App-Name" > Berechtigungen> Speicher

Ravi Joshi
quelle
Dies ist in meinem Fall die richtige Lösung. Es erfordert keine Änderung des Codes und gilt für alle Apps, die auf Lollipop funktionieren, ist jedoch nicht an das neue Konzept des Marshmallow angepasst, Berechtigungen zur Laufzeit zu erteilen .
GoranM
Was ist mit dem internen Speicher?
Igor Ganapolsky
8

Aus der Methodendokumentation der Datei 'listFiles': Gibt null zurück, wenn dieser abstrakte Pfadname kein Verzeichnis angibt oder wenn ein E / A-Fehler auftritt.

Möglicherweise ist also ein E / A-Fehler aufgetreten. Überprüfen Sie die Berechtigungen für dieses Verzeichnis. Hat der Benutzer, der das Java-Programm ausführt, die Berechtigung, dieses Verzeichnis zu lesen? Wenn nicht, gibt es Ihre Antwort. Wenn ja, ist das Verzeichnis möglicherweise leer.

Übrigens sollten Sie nicht + "" verwenden, um etwas in einen String zu konvertieren. Dies ist eine schlechte Vorgehensweise, da es langsamer als String.valueOf ist. Ich würde StringUtils von Apache verwenden, um dieses Array zu einem String zu verbinden, aber dazu muss dieses Jar zu Ihrem Klassenpfad hinzugefügt werden.

msknapp
quelle
4

Fügen Sie einfach die Berechtigung im Manifest hinzu uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" und Ihr Problem wird behoben.

Kamal
quelle
2

Die Antwort von @ tamo hat mein Problem behoben. Ich kompiliere den Exoplayer auf ANQ und setze:

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">

Ich überprüfe die Android-Entwicklungsseite und erkläre dies bereits: https://developer.android.com/training/data-storage/compatibility

Wenn Sie auf API 29 oder höher abzielen, folgen Sie einfach den Einstellungen von Google.

franke.wu
quelle
1

Mein Problem war, dass das Attribut android: sharedUserId = "android.uid.system" aus irgendeinem Grund der App nicht erlaubte, / sdcard / auf einem bestimmten Gerät zu lesen.

Da ich nur einen kurzen Test durchführen musste, entfernte ich das sharedUserId-Attribut, testete es und fügte es wieder hinzu.

thiagolr
quelle
0

Ich hatte das gleiche Problem in Java, aber nicht in Android, wo ich Konfigurationsdatei mit Pfad in Anführungszeichen lese. Ich habe mein Problem gelöst, indem ich nur Anführungszeichen entfernt habe

Sie können dies also mit der Funktion "Zeichenfolge ersetzen" oder ohne Anführungszeichen tun

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

Sam
quelle
-1

Fügen Sie in der Manifestdatei im <uses-permission .... >Abschnitt diese Zeile hinzu android:name="android.permission.READ_EXTERNAL_STORAGE". Ich denke, das könnte Ihr Problem lösen.

Rajan Menon
quelle
3
Ist das nicht nur eine Wiederholung der vorhandenen Antworten?
Pang