Öffnen fehlgeschlagen: EACCES (Berechtigung verweigert)

70

Ich habe ein sehr seltsames Problem mit dem Speicherzugriff auf einigen Geräten. Die App funktioniert auf meinen Testgeräten (Nexus 4 & 7, Samsung GS5). Alle meine Geräte mit Android 4.4.2. Aber ich habe viele E-Mails von Benutzern erhalten, die besagten, dass die App nicht in den Speicher schreiben kann (weder in den internen Speicher noch in die SD-Karte). Aus der Protokolldatei, die vom Benutzerfeedback erhalten wurde, geht hervor, dass das Problem der folgende Code ist:

try {
    if (fStream == null) {
    fStream = new FileOutputStream(filename, true);
}
    fStream.write(data, 0, bytes);
    return;
} catch (IOException ex) {
    ex.printStackTrace();
}

Es wird eine Ausnahme in der Zeile fStream = new FileOutputStream (Dateiname, true) ausgelöst. beim Erstellen von FileOutputStream.

Das Stapelprotokoll lautet:

W/System.err( 8147): Caused by: java.io.FileNotFoundException: /storage/emulated/0/my_folder/test_file_name.png: open failed: EACCES (Permission denied)
w/System.err( 8147):    at libcore.io.IoBridge.open(IoBridge.java:409)
W/System.err( 8147):    at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
W/System.err( 8147):    at java.io.FileOutputStream.<init>(FileOutputStream.java:128)
W/System.err( 8147):    at myapp.save(SourceFile:515)
W/System.err( 8147):    ... 8 more
W/System.err( 8147): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
W/System.err( 8147):    at libcore.io.Posix.open(Native Method)
W/System.err( 8147):    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
W/System.err( 8147):    at libcore.io.IoBridge.open(IoBridge.java:393)
W/System.err( 8147):    ... 11 more

In der AndroidManifest.xml habe ich folgende Berechtigungen deklariert:

 <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19"/>
    <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

Ich habe bestätigt, dass die Benutzer die private App der richtigen App auf der SD-Karte verwenden. Und was noch seltsamer ist, dass es nicht auch in den internen Speicher schreibt. Wie kann dies passieren, wenn ich sowohl Lese- als auch Schreibberechtigungen habe? Die Benutzer geben an, dass sie ihre Geräte zu diesem Zeitpunkt nicht an den PC anschließen.

Aktualisieren

Es stellt sich heraus, dass ich FileOutputStream zu häufig zum Öffnen und Schließen aufrufe, wodurch irgendwann die FileNotFoundException ausgelöst wird. Klingt eher nach einem Threading-Problem.

user3613696
quelle
Es stellt sich heraus, dass ich FileOutputStream zu häufig zum Öffnen und Schließen aufrufe, wodurch irgendwann die FileNotFoundException ausgelöst wird. Klingt eher nach einem Threading-Problem.
user3613696
Überprüfen Sie meine Antwort hier. ich hoffe es hilft. stackoverflow.com/a/58797938/11696949
Zeeshan Fareed

Antworten:

35

Ich bin vor einiger Zeit auf ein ähnliches Problem gestoßen.

Ihr Problem kann in zwei verschiedenen Bereichen liegen. Entweder erstellen Sie die Datei, in die Sie schreiben möchten, oder Ihre Schreibmethode ist möglicherweise fehlerhaft, da sie vom Telefon abhängig ist.

Wenn Sie die Datei an einen bestimmten Speicherort auf der SD-Karte schreiben, verwenden Sie Umgebungsvariablen. Sie sollten immer auf einen gültigen Ort verweisen. Hier ist ein Beispiel zum Schreiben in den Download-Ordner:

java.io.File xmlFile = new java.io.File(Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
     + "/Filename.xml");

Wenn Sie die Datei in den internen Speicher der Anwendung schreiben. Versuchen Sie dieses Beispiel:

java.io.File xmlFile = new java.io.File((getActivity()
   .getApplicationContext().getFileStreamPath("FileName.xml")
   .getPath()));

Persönlich verlasse ich mich auf externe Bibliotheken, um das Streaming in eine Datei zu verwalten. Dieser hat mich noch nicht im Stich gelassen.

org.apache.commons.io.FileUtils.copyInputStreamToFile(is, file);

Ich habe bei einem fehlgeschlagenen Schreibbefehl zu oft Daten verloren, daher verlasse ich mich bei meinem schweren E / A-Heben auf bekannte und getestete Bibliotheken.

Wenn die Dateien groß sind, können Sie auch die Ausführung der E / A im Hintergrund untersuchen oder Rückrufe verwenden.

Wenn Sie bereits Umgebungsvariablen verwenden, kann dies ein Berechtigungsproblem sein. Schauen Sie sich die Antwort von Justin Fiedler unten an.

Dachkammer
quelle
Ich werde es mit org.apache.commons.io.FileUtils versuchen und sehen, ob das hilft. Wird später aktualisiert. Übrigens stellt sich nach weiteren Tests heraus, dass fStream = new FileOutputStream (Dateiname, true); öffnet den Stream nicht immer jedes Mal, sieht aus, als würde er zum ersten Mal funktionieren und schlägt beim nächsten Mal fehl.
user3613696
1
Es stellt sich heraus, dass ich FileOutputStream zu häufig zum Öffnen und Schließen aufrufe, wodurch irgendwann die FileNotFoundException ausgelöst wird. Klingt eher nach einem Threading-Problem. Ich habe Ihre Antwort als akzeptiert markiert, da Sie auf den möglichen Fehler richtig hingewiesen haben.
user3613696
Vielen Dank. Ja, da wir nicht Ihren gesamten Code sehen konnten, müssen wir nur einige Vermutungen anstellen, was Ihr Problem verursachen könnte. Danke für's Annehmen!
Garret
129

Für API 23+ müssen Sie die Lese- / Schreibberechtigungen anfordern, auch wenn sie bereits in Ihrem Manifest enthalten sind.

// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

/**
 * Checks if the app has permission to write to device storage
 *
 * If the app does not has permission then the user will be prompted to grant permissions
 *
 * @param activity
 */
public static void verifyStoragePermissions(Activity activity) {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(
                activity,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Justin Fiedler
quelle
1
Das stimmt, hat mein Problem gelöst. Weitere Informationen: developer.android.com/training/permissions/requesting.html
Joaobarbosa
Genau, mein Problem war ähnlich. Wenn ich die App in Android-Versionen unter v6 getestet habe. Die App funktionierte wie ein Zauber, aber für> = 6 stimmte etwas nicht. Wie @easyspeak sagte, fügen Sie einfach eine Berechtigungsanforderung hinzu.
Shudy
Wie geht das bei einem instrumentierten Test?
Ahmad Muzakki
Ich gab Erlaubnis, aber nicht in der Lage, .zip-Datei in SD-Karte zu machen
Bhanu Sharma
2
Dies ist die richtige Antwort, nicht die aktuell markierte.
Hdante
128

Apps, die standardmäßig auf Android Q - API 29 abzielen, erhalten eine gefilterte Ansicht in den externen Speicher. Eine schnelle Lösung dafür ist das Hinzufügen dieses Codes in der AndroidManifest.xml:

<manifest ... >
    <!-- This attribute is "false" by default on apps targeting Android Q. -->
    <application android:requestLegacyExternalStorage="true" ... >
     ...
    </application>
</manifest>

Lesen Sie hier mehr darüber: https://developer.android.com/training/data-storage/compatibility

Uriel Frankel
quelle
Hat meinen Tag gerettet. Viel gesucht, aber diese Antwort nirgendwo gefunden. Das ist richtig.
Tejas Pandya
1
Da diese Lösung nur vorübergehend ist, finden Sie hier die gesamte Implementierung zum Abfragen der Mediendateien: developer.android.com/training/data-storage/shared/media . Wenn es sich um ein Bild handelt, müssen Sie nach Erhalt der URL ContentResolver.loadThumbnail (URL, Größe, CancelSignal) aufrufen, um die Bitmap mit diesem Bild zu erhalten.
Sunlover3
1
Mann, du hast einen Bonus verdient
Daniel Beltrami
Beim Kompilieren wird ein Fehler ausgegeben: Attribut android: requestLegacyExternalStorage nicht gefunden.
Priyanka Singhal
@Priyanka bitte schauen Sie sich den Link an, den ich hinzugefügt habe
Uriel Frankel
6

In meinem Fall hatte ich den falschen Fall in

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

android.permission muss klein geschrieben sein, und irgendwie war die gesamte Zeichenfolge in unserer Quelle in Großbuchstaben geschrieben.

Graham Perks
quelle
5

Ich stand auch vor dem gleichen Problem. Nach viel harter Arbeit fand ich heraus, was in meinem Fall falsch war. Mein Gerät wurde über ein USB-Kabel mit dem Computer verbunden. Es gibt Typen für USB-Verbindungen wie Massenspeicher, Mediengerät (MTP), Kamera (PTP) usw. Mein Verbindungstyp war - "Massenspeicher", und dies verursachte die Probleme. Als ich den Verbindungstyp änderte, wurde das Problem behoben.

Denken Sie beim Zugriff auf das Dateisystem auf einem Android-Gerät immer daran: -

NICHT ALS MASSENSPEICHER an den Computer / PC anschließen.

ninad.sonje
quelle
4
Geändert zu was? Ich habe PTP und MTP als meine einzigen Optionen, beide funktionieren nicht. Selbst wenn Sie die App auf mein Gerät laden und vom Gerät aus starten, ohne dass sie mit meinem Computer verbunden ist, wird dies nicht behoben.
G_V
Oder debuggen Sie es mit Wifi.
David
3

In meinem Fall handelte es sich um ein Berechtigungsproblem. Der Haken ist, dass ich auf einem Gerät mit Android 4.0.4 ohne Fehler oder Ausnahmen Zugriff auf die Datei habe. Und auf Geräten mit Android 5.1 ist es mit der ACCESS-Ausnahme fehlgeschlagen (Öffnen fehlgeschlagen: EACCES (Berechtigung verweigert)). Behandelte es mit dem Hinzufügen der folgenden Berechtigung zum Manifestieren der Datei:

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

Ich denke also, dass es der Unterschied zwischen der Berechtigungsverwaltung in Betriebssystemversionen ist, der zu Fehlern führt.

Anton Vaysberg
quelle
2

Geben oder überprüfen Sie zuerst Berechtigungen wie

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

Wenn diese beiden Berechtigungen in Ordnung sind, überprüfen Sie, ob Ihre Ausgabestreams im richtigen Format vorliegen.

Beispiel:

FileOutputStream fos=new FileOutputStream(Environment.getExternalStorageDirectory()+"/rahul1.jpg");
Rahul
quelle
2

Ich bin auf dasselbe Problem gestoßen und habe festgestellt, dass ich die Berechtigungen zur Laufzeit anfordern muss, auch wenn ich sie im Manifest deklariert habe. Genau wie die Antwort von Justin Fiedler.

Die offizielle Dokumentation dazu finden Sie hier: https://developer.android.com/training/permissions/requesting.html

Meine Implementierung unterscheidet sich geringfügig von der Antwort von Justin Fiedler, dass sie auch die onRequestPermissionsResult-Methode des v4-Fragments implementiert, um die Antwort auf die Berechtigungsanforderung zu verarbeiten.

public static final int REQUEST_EXTERNAL_PERMISSION_CODE = 666;

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static final String[] PERMISSIONS_EXTERNAL_STORAGE = {
        READ_EXTERNAL_STORAGE,
        WRITE_EXTERNAL_STORAGE
};

public boolean checkExternalStoragePermission(Activity activity) {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
        return true;
    }

    int readStoragePermissionState = ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
    int writeStoragePermissionState = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
    boolean externalStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED &&
            writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
    if (!externalStoragePermissionGranted) {
        requestPermissions(PERMISSIONS_EXTERNAL_STORAGE, REQUEST_EXTERNAL_PERMISSION_CODE);
    }

    return externalStoragePermissionGranted;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == REQUEST_EXTERNAL_PERMISSION_CODE) {
            if (checkExternalStoragePermission(getActivity())) {
                // Continue with your action after permission request succeed
            }
        }
    }
}
Alex Bin Zhao
quelle
Tolle Illustration. Hat meinen Tag gerettet. :-)
TechBee
1

In meinem Fall habe ich die Option android:isolatedProcess="true"für ein servicein der verwendet AndroidManifest.xml.

Sobald ich es entfernt habe, ist der Fehler verschwunden ...

Dolch
quelle
1

Auch ich fand Lösung für meinen Weg.

Vor dem Start der App habe ich dem Datei-Explorer root gewährt und die Berechtigung zum Schreiben / Lesen beim Beenden der App nicht deaktiviert.

Meine App kann keinen externen Speicher verwenden, während ich das Gerät zum Zurücksetzen aller Berechtigungen restratiert habe.

Kaftanati
quelle
1

Ich habe das gleiche Problem, aber manchmal wird das schwierigste Problem einfach beantwortet.

Ich überprüfe die Manifest-Berechtigungen erneut und dort WAS_NOT schreiben Sie die Berechtigungsschande von mir !!!

San Juan
quelle
Jesus Christus, das ist mir gerade passiert, danke Haufen
Juanca
1

@Uriel Frankel ist richtig, dass sich der Android 10-Speicherzugriff geändert hat. Der richtige Weg ist jedoch, nicht das Legacy-Speicherflag zu verwenden, sondern den Speicher Ihrer App wie folgt anzufordern:

val screenShotDirPath = getApplication<Application>().getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.path

getExternalFilesDir ist das, was Sie brauchen.

Regenmacher
quelle
0

Wenn die Clients Android 6.0 verwenden, hat Android ein neues Berechtigungsmodell für (Marshmallow) hinzugefügt .

Trick: Wenn Sie auf Version 22 oder niedriger abzielen, fordert Ihre Anwendung bei der Installation alle Berechtigungen an, genau wie auf jedem Gerät, auf dem ein Betriebssystem unter Marshmallow ausgeführt wird

Nourdine Alouane
quelle
0

In meinem Fall war das Problem, dass die statische WIFI-Konfiguration einen Konflikt mit einem anderen Gerät hatte, das dieselbe IP-Adresse verwendet.

lloyd
quelle
0

Fügen Sie diese Lese- und Schreibberechtigung hinzu, um dieses Problem zu beheben

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

Fügen Sie diese folgende Zeile im Anwendungs-Tag hinzu

android:requestLegacyExternalStorage="true"
Omesh Kumar
quelle
0

Dieser Fehler wurde von einer anderen App ausgelöst, für die ich die Datei meiner App freigebe (mit Intent.FLAG_GRANT_READ_URI_PERMISSION)

Es stellt sich heraus, dass die Datei wie hier gezeigt Uriüber die FileProviderKlasse bereitgestellt werden muss .

Ameise
quelle
-3

In meinem Fall habe ich vergessen, / vor dem Dateinamen hinzuzufügen, nachdem ich hinzugefügt habe, habe ich ihn entfernt

bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(Environment.getExternalStorageDirectory()+"/arjunreddy.png"));
Sai Gopi ich
quelle