Exception «ouverture échouée: EACCES (autorisation refusée)» sur Android

298

Je reçois

échec d'ouverture: EACCES (Permission denied)

sur la ligne OutputStream myOutput = new FileOutputStream(outFileName);

J'ai vérifié la racine et j'ai essayé android.permission.WRITE_EXTERNAL_STORAGE.

Comment puis-je résoudre ce problème?

try {
    InputStream myInput;

    myInput = getAssets().open("XXX.db");

    // Path to the just created empty db
    String outFileName = "/data/data/XX/databases/"
            + "XXX.db";

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // Transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();
    buffer = null;
    outFileName = null;
}
catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}
Mert
la source
J'ai eu le même problème sur une tablette Android, mais ma situation est peut-être unique, je rapporte donc ma solution ici dans un commentaire. L'erreur s'est produite lorsque l'application a tenté d'accéder au répertoire / data / data / myapp / foo qui contenait plus de 50 fichiers xml. L'application n'a pas nettoyé le dossier en raison d'un bogue. Après la suppression de certains anciens fichiers, l'erreur a disparu. Je ne sais pas pourquoi. Il pourrait s'agir d'un problème lié à l'appareil Android générique.
Hong
Cela m'a résolu: stackoverflow.com/questions/33666071/…
partho

Réponses:

236

J'ai eu le même problème ... <uses-permissionC'était au mauvais endroit. C'est juste:

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

La uses-permissionbalise doit être en dehors de la applicationbalise.

user462990
la source
2
c'est que l'autorisation uses doit être en dehors de l'application
user462990
3
Je reçois un avertissement: "la <uses-permission>balise apparaît après la <application>balise"
mr5
11
AVERTISSEMENT Dans Android 4.4.4, n'utilisez pas le paramètre android:maxSdkVersion="18". Il générait cette exception
guisantogui
1
Cette autorisation est appliquée à partir du niveau 19 de l'API. Avant le niveau 19 de l'API, cette autorisation n'est pas appliquée et toutes les applications ont toujours accès à la lecture à partir du stockage externe.
Zar E Ahmer
1
im en utilisant l'API lvl 15, je reçois une erreur lors de la tentative de déplacement du fichier vers la clé USB OTG
Ravi Mehta
330

Pour l'API 23+, vous devez demander les autorisations de lecture / écriture même si elles se trouvent déjà dans votre manifeste.

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

Pour obtenir de la documentation officielle sur la demande d'autorisations pour l'API 23+, consultez https://developer.android.com/training/permissions/requesting.html

Justin Fiedler
la source
13
Juste pour clarifier, pour que cela fonctionne, l'activité doit gérer la réponse de la demande d'autorisations d'activité. Voir developer.android.com/training/permissions/… pour plus de détails.
kldavis4
Lien pratique avec explication et exemples ici dansthecheesefactory.com/blog/…
Paul Alexander
1
n'est-ce pas une mauvaise chose? en ce qui concerne l'expérience utilisateur.
M. Usman Khan,
5
Mais où dois-je l'utiliser? par exemple, si je veux prendre une photo, dois-je exécuter verifyStoragePermissions avant startActivityForResult ou sur onActivityResult? ça me déroute vraiment.
Kiwi Lee
3
Merci cela résout mon problème. juste une note: si quelqu'un ne peut pas résoudre "Manifest.permission", il vous suffit d'importer "import android.Manifest".
Oubaida AlQuraan
169

Google a une nouvelle fonctionnalité sur Android Q : vue filtrée pour le stockage externe. Une solution rapide pour cela consiste à ajouter ce code dans le fichier AndroidManifest.xml:

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

Vous pouvez en savoir plus à ce sujet ici: https://developer.android.com/training/data-storage/compatibility

Uriel Frankel
la source
@Billy j'ai remarqué que cela ne se produit que sur les appareils avec api 29. J'ai donc recherché des changements dans le fournisseur de fichiers
Uriel Frankel
J'ai enfin obtenu le cloudtestingscreenshotter_lib.aar pour travailler avec cette ligne ajoutée au manifeste androidTest, merci beaucoup pour cette découverte.
bko
6
Vous monsieur, m'a sauvé beaucoup de temps. Beaucoup de choses sont devenues pénibles pour un développeur en Q. Je pense que cette réponse devrait être publiée comme une question distincte et mérite plus de votes positifs.
sanjeev
Je voudrais en savoir plus sur ce joli petit tour de magie noire, mais malheureusement le lien renvoie une erreur 404 ... Merci quand même
SadSido
son donner un avertissement android:requestLegacyExternalStorage="true"ce ne cassera pas les versions inférieures ryt? @UrielFrankel
Santanu Sur
58

J'ai observé cela une fois lors de l'exécution de l'application à l'intérieur de l'émulateur. Dans les paramètres de l'émulateur, vous devez spécifier correctement la taille du stockage externe ("carte SD"). Par défaut, le champ "stockage externe" est vide, ce qui signifie probablement qu'il n'y a pas de périphérique de ce type et que EACCES est levé même si des autorisations sont accordées dans le manifeste.

Audrius Meskauskas
la source
51

En plus de toutes les réponses, assurez-vous que vous n'utilisez pas votre téléphone comme stockage USB.

J'avais le même problème sur HTC Sensation sur le mode de stockage USB activé. Je peux toujours déboguer / exécuter l'application, mais je ne peux pas enregistrer sur un stockage externe.

John
la source
Merci mec, même si j'avais demandé des autorisations à l'utilisateur au moment de l'exécution. Cette erreur s'est produite sur l'émulateur.
Sharp Edge
1
Lorsque je connecte l'appareil Samsung Galaxy S6, il donne d'abord une option "Autoriser l'accès aux données de l'appareil" avec "REFUSER" ou "AUTORISER" et également à partir de la barre de notification, j'obtiens une option Utiliser USB pour 1. MTP 2. PTP 3. MIDI Appareils 4. Chargement. Lequel choisir?
testsingh
34

Ajouter android: requestLegacyExternalStorage = "true" à l'Android Manifest Il a travaillé avec Android 10 (Q) au SDK 29+
ou après la migration Android X .

 <application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:hardwareAccelerated="true"
    android:icon=""
    android:label=""
    android:largeHeap="true"
    android:supportsRtl=""
    android:theme=""
    android:requestLegacyExternalStorage="true">
rhaldar
la source
Wow fonctionne parfaitement, c'était la réponse que je cherchais, super, merci @rhaldar, tu m'as sauvé la journée
Ayush Katuwal
29

Mon problème était avec "TargetApi (23)" qui est nécessaire si votre version minSdk est inférieure à 23.

J'ai donc demandé la permission avec l'extrait de code suivant

protected boolean shouldAskPermissions() {
    return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
}

@TargetApi(23)
protected void askPermissions() {
    String[] permissions = {
            "android.permission.READ_EXTERNAL_STORAGE",
            "android.permission.WRITE_EXTERNAL_STORAGE"
    };
    int requestCode = 200;
    requestPermissions(permissions, requestCode);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
// ...
    if (shouldAskPermissions()) {
        askPermissions();
    }
}
Piroxiljin
la source
28

Solution pour Android Q :

<application ...
    android:requestLegacyExternalStorage="true" ... >
mubin986
la source
Tu m'as sauvé la journée. L'autorisation est accordée, mais Glide ne peut pas lire les images tant que je ne l'ai pas défini.
leegor
Attention: Android 11 supprimera complètement l'accès hérité en août 2020, donc améliorez l'accès aux fichiers pour utiliser Storage Access Framework (SAF) pour vos applications
dimib
16

Je vis la même chose. Ce que j'ai trouvé, c'est que si vous allez dans Paramètres -> Gestionnaire d'applications -> Votre application -> Autorisations -> Activer le stockage , cela résout le problème.

Atul Kaushik
la source
1
Je ne trouve pas cette section?
Evan Sevy
13

Il s'est avéré que c'était une erreur stupide car mon téléphone était toujours connecté au PC de bureau et je ne m'en étais pas rendu compte.

J'ai donc dû désactiver la connexion USB et tout a bien fonctionné.

Tobias Reich
la source
travaillé pour moi aussi. Mais pourquoi ça marche? quelle différence ne fait pas la connexion USB au PC.
user13107
Bonne question. Je n'ai jamais enquêté davantage sur cela. Je suppose qu'il y a un verrouillage en écriture du système au moment où vous connectez l'appareil (il peut donc émuler un périphérique USB sur votre ordinateur). C'est peut-être pour éviter des données incohérentes. Pas sûr cependant.
Tobias Reich
J'ai trouvé la raison ici stackoverflow.com/questions/7396757/… voir aussi ma réponse stackoverflow.com/a/43863548/1729501
user13107
13

J'ai eu le même problème sur Samsung Galaxy Note 3, exécutant CM 12.1. Le problème pour moi était que j'avais

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

et a dû l'utiliser pour prendre et stocker des photos d'utilisateurs. Lorsque j'ai essayé de charger ces mêmes photos dans ImageLoader, j'ai eu l' (Permission denied)erreur. La solution consistait à ajouter explicitement

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

car l'autorisation ci-dessus limite uniquement l'autorisation d'écriture jusqu'à la version 18 de l'API, et avec elle l'autorisation de lecture.

ZooS
la source
Ne m'a pas aidé! Ça vaut le coup! Merci.
Sakiboy
9

En plus de toutes les réponses, si les clients utilisent Android 6.0, Android a ajouté un nouveau modèle d'autorisation pour (Marshmallow).

Astuce: si vous ciblez la version 22 ou inférieure, votre application demandera toutes les autorisations au moment de l'installation, comme sur n'importe quel appareil exécutant un système d'exploitation sous Marshmallow. Si vous essayez l'émulateur, à partir d'Android 6.0, vous devez explicitement accéder aux paramètres -> applications -> YOURAPP -> autorisations et modifier l'autorisation si vous en avez donné.

Nourdine Alouane
la source
2
Incroyable, j'ai passé 2 jours à essayer de comprendre cela. Chaque fois que je sens que les choses se passent bien sur Android, quelque chose comme ça se produit.
Jaime Ivan Cervantes
7

Étrangement, après avoir mis une barre oblique "/" avant mon nouveau fichier, mon problème a été résolu. J'ai changé ça:

File myFile= new File(Environment.getExternalStorageDirectory() + "newFile");

pour ça:

File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");
Darush
la source
1
Rien d'étrange ici. Avec la première ligne, vous essayez de créer un fichier dans le même répertoire que celui qui contient votre répertoire de stockage externe. ie /storage/.../somethingnewfile au lieu de /storage/.../something/newfile
Stéphane
@ Stéphane L'erreur elle-même est étrange si l'on regarde le large éventail de réponses.
Darush
3
La façon correcte de le faire est d'utiliser le cosntructeur File (dir, file)
Nick Cardoso
@NickCardoso Vous pouvez également utiliser File (String pathname). On dirait que vous n'obtenez pas le point ici. La question n'est pas de savoir comment utiliser la classe File. La gamme de réponses dans ce fil montre à quel point cette erreur est trompeuse et combien de façons possibles de la résoudre. Dans mon cas, l'erreur était la barre oblique manquante. Certaines personnes l'ont trouvé utile. Bien sûr, vous pouvez utiliser votre propre méthode d'accès à un fichier. Allez-y et postez votre réponse. Cela peut résoudre le problème de quelqu'un.
Darush
Vous n'obtenez pas le point. Si vous utilisez le bon constructeur, votre hack n'est pas nécessaire. Mon commentaire a été ajouté afin qu'il puisse aider tous les futurs lecteurs induits en erreur par votre erreur. Ce n'était pas une critique personnelle et n'avait pas besoin de réponse
Nick Cardoso
6

J'ai eu le même problème et aucune des suggestions n'a aidé. Mais j'ai trouvé une raison intéressante à cela, sur un appareil physique, Galaxy Tab .

Lorsque le stockage USB est activé, les autorisations de lecture et d'écriture sur le stockage externe n'ont aucun effet. Désactivez simplement le stockage USB et avec les autorisations appropriées, le problème sera résolu.

Hamlet Kraskian
la source
2
Merde, je viens de passer environ 3 heures à travailler. De plus, j'ai dû redémarrer l'appareil et cela a fonctionné. Merci beaucoup
crgarridos
5

Je m'attendrais à ce que tout ce qui suit fasse /datapartie du "stockage interne". Vous devriez cependant pouvoir écrire /sdcard.

four
la source
5
J'ai également essayé <uses-permission android: name = "android.permission.WRITE_INTERNAL_STORAGE" />. toujours pareil.
Mert
1
La partition / data est généralement protégée en écriture pour les utilisateurs ordinaires (non root) essayant d'accéder aux fichiers ordinaires. Pour le stockage interne, il existe des méthodes spécialisées pour ce faire, surtout si vous souhaitez accéder aux bases de données. Les pages des développeurs Android devraient vous aider sur ce problème.
fourror
5

Modifiez une propriété d'autorisation dans votre /system/etc/permission/platform.xml
et besoin de groupe comme mentionné ci-dessous.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
    <group android:gid="sdcard_rw" />
    <group android:gid="media_rw" />    
</uses-permission>
Prabakaran
la source
platform.xml est verrouillé vers le bas, en tentant cela via le shell adb, mais j'ai besoin du script ADB qui me permettra d'utiliser le mod.
John
Échouer. Mettez mon appareil dans une boucle de démarrage.
Tobse
5

J'ai eu la même erreur lorsque j'essayais d'écrire une image dans le dossier DCIM / camera sur Galaxy S5 (android 6.0.1) et j'ai compris que seul ce dossier était restreint. Je pourrais simplement écrire dans DCIM / n'importe quel dossier mais pas à huis clos. Cela devrait être une restriction / personnalisation basée sur la marque.

Mahdi Mehrizi
la source
4

Lorsque votre application appartient à l'application système, elle ne peut pas accéder à la carte SD.

volonté
la source
4

gardez à l'esprit que même si vous définissez toutes les autorisations correctes dans le manifeste: le seul endroit où les applications tierces sont autorisées à écrire sur votre carte externe sont "leurs propres répertoires" (c'est-à-dire / sdcard / Android / data /) essayant d'écrire dans n'importe où ailleurs: vous obtiendrez une exception: EACCES (Autorisation refusée)

Elad
la source
3

Peut-être que la réponse est la suivante:

sur l'API> = 23 appareils, si vous installez l'application (l'application n'est pas une application système), vous devez vérifier l'autorisation de stockage dans "Paramètres - applications", il existe une liste d'autorisations pour chaque application, vous devez la vérifier! essayer

Jason Zhu
la source
3

Dans mon cas, j'utilisais une bibliothèque de sélecteur de fichiers qui renvoyait le chemin vers le stockage externe, mais cela a commencé à partir de /root/. Et même avec l' autorisation WRITE_EXTERNAL_STORAGE accordée au moment de l'exécution, j'ai quand même eu l'erreur EACCES (autorisation refusée) .
Alors utilisezEnvironment.getExternalStorageDirectory() pour obtenir le chemin d'accès correct au stockage externe.

Exemple:
impossible d'écrire: /root/storage/emulated/0/newfile.txt
peut écrire: /storage/emulated/0/newfile.txt

boolean externalStorageWritable = isExternalStorageWritable();
File file = new File(filePath);
boolean canWrite = file.canWrite();
boolean isFile = file.isFile();
long usableSpace = file.getUsableSpace();

Log.d(TAG, "externalStorageWritable: " + externalStorageWritable);
Log.d(TAG, "filePath: " + filePath);
Log.d(TAG, "canWrite: " + canWrite);
Log.d(TAG, "isFile: " + isFile);
Log.d(TAG, "usableSpace: " + usableSpace);

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

Sortie 1:

externalStorageWritable: true
filePath: /root/storage/emulated/0/newfile.txt
isFile: false
usableSpace: 0

Sortie 2:

externalStorageWritable: true
filePath: /storage/emulated/0/newfile.txt
isFile: true
usableSpace: 1331007488
vovahost
la source
J'avais exactement le même problème. La suppression de la rootpièce du chemin a résolu mon problème.
xabush
3
Environment.getExternalStoragePublicDirectory();

Lorsque vous utilisez cette méthode obsolète à partir d'Android 29, vous recevrez la même erreur:

java.io.FileNotFoundException: open failed: EACCES (Permission denied)

Résolution ici:

getExternalStoragePublicDirectory déconseillé dans Android Q

user2965003
la source
3

Pour toute personne venant des résultats de recherche et ciblant Android 10: Android 10 (API 29) modifie certaines autorisations liées au stockage.

J'ai résolu le problème en remplaçant mes instances précédentes de Environment.getExternalStorageDirectory()(qui est obsolète avec l'API 29) parcontext.getExternalFilesDir(null) .

Notez que context.getExternalFilesDir(type) peut retourner null si l'emplacement de stockage n'est pas disponible, assurez-vous donc de vérifier que chaque fois que vous vérifiez si vous avez des autorisations externes.

Lisez plus ici .

jacoballenwood
la source
2

Je crée un dossier sous / data / dans mon init.rc (déblayage avec l'aosp sur Nexus 7) et j'ai eu exactement ce problème.

Il s'est avéré que donner l'autorisation au dossier rw (666) n'était pas suffisant et il fallait que ce soit rwx (777) alors tout a fonctionné!

voie
la source
2

L'application des autorisations de stockage après 6.0 peut être contournée si vous avez un périphérique enraciné via ces commandes adb:

root@msm8996:/ # getenforce
getenforce
Enforcing
root@msm8996:/ # setenforce 0
setenforce 0
root@msm8996:/ # getenforce
getenforce
Permissive
Zakir
la source
1

Ajoutez l'autorisation dans le manifeste.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Harman Khera
la source
3
Il n'y a aucune autorisationandroid.permission.READ_INTERNAL_STORAGE
Ryan R
0

J'ai eu le même problème (API> = 23).

La solution https://stackoverflow.com/a/13569364/1729501 a fonctionné pour moi, mais il n'était pas pratique de déconnecter l'application pour le débogage.

ma solution était d'installer le pilote de périphérique adb approprié sur Windows. Le pilote USB Google ne fonctionnait pas pour mon appareil.

ÉTAPE 1: Téléchargez les pilotes adb pour la marque de votre appareil.

ÉTAPE 2: Accédez au gestionnaire de périphériques -> autres périphériques -> recherchez les entrées avec le mot "adb" -> sélectionnez Mettre à jour le pilote -> indiquez l'emplacement à l'étape 1

user13107
la source
0

après avoir ajouté l'autorisation a résolu mon problème

<uses-permission android:name="android.permission.INTERNET"/>
Sai Gopi N
la source
0

Ajouter des dépendances Gradle

implementation 'com.karumi:dexter:4.2.0'

Ajoutez le code ci-dessous dans votre activité principale.

import com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
    @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_splash);

    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {


                checkMermission();
            }
        }, 4000);
    }

    private void checkMermission(){
        Dexter.withActivity(this)
                .withPermissions(
                        android.Manifest.permission.READ_EXTERNAL_STORAGE,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        android.Manifest.permission.ACCESS_NETWORK_STATE,
                        Manifest.permission.INTERNET
                ).withListener(new MultiplePermissionsListener() {
            @Override
            public void onPermissionsChecked(MultiplePermissionsReport report) {
                if (report.isAnyPermissionPermanentlyDenied()){
                    checkMermission();
                } else if (report.areAllPermissionsGranted()){
                    // copy some things
                } else {
                    checkMermission();
                }

            }
            @Override
            public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                token.continuePermissionRequest();
            }
        }).check();
    }
éthemsulan
la source
0

Dans mon cas, l'erreur apparaissait sur la ligne

      target.createNewFile();

car je ne pouvais pas créer un nouveau fichier sur la carte SD, j'ai donc dû utiliser l'approche DocumentFile.

      documentFile.createFile(mime, target.getName());

Pour la question ci-dessus, le problème peut être résolu avec cette approche,

    fos=context.getContentResolver().openOutputStream(documentFile.getUri());

Voir aussi ce fil, Comment utiliser la nouvelle API d'accès à la carte SD présentée pour Android 5.0 (Lollipop)?

Tarasantan
la source