web-dev-qa-db-fra.com

open failed: EACCES (autorisation refusée)

J'ai un très étrange problème d'accès au stockage sur certains appareils. L'application fonctionne sur mes appareils de test (Nexus 4 et 7, Samsung GS5). Tous mes appareils fonctionnant sous Android 4.4.2. Mais j'ai reçu de nombreux courriels d'utilisateurs qui me diraient que l'application ne peut pas écrire sur le stockage (ni sur le stockage interne ni sur la carte SD). À partir du fichier journal reçu des commentaires des utilisateurs, je peux voir que le problème est le code suivant:

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

Il lève une exception à la ligne fStream = new FileOutputStream (nomfichier, true); lors de la création de FileOutputStream.

Le journal de pile est:

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

Dans le fichier AndroidManifest.xml, les autorisations suivantes sont déclarées:

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

J'ai confirmé que les utilisateurs utilisaient la confidentialité de l'application correcte sur la carte SD. Et ce qui est plus étrange, c'est qu'il n'écrit pas non plus dans la mémoire interne. Comment cela peut-il se produire si j'ai à la fois des autorisations de lecture et d'écriture? Les utilisateurs disent qu'ils ne connectent pas leurs appareils au PC à ce moment-là.

Mise à jour

Il s'avère que j'appelle ouvrir et fermer FileOutputStream trop fréquemment, ce qui lève l'exception FileNotFoundException à un moment donné. Cela ressemble plus à un problème de filetage.

55
user3613696

J'ai rencontré un problème similaire il y a quelque temps.

Votre problème pourrait être dans deux domaines différents. C’est soit la façon dont vous créez le fichier dans lequel vous écrivez, soit votre méthode d’écriture risque d’être erronée car elle dépend du téléphone.

Si vous écrivez le fichier dans un emplacement spécifique de la carte SD, essayez d’utiliser des variables d’environnement. Ils doivent toujours indiquer un emplacement valide. Voici un exemple pour écrire dans le dossier de téléchargement:

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

Si vous écrivez le fichier dans la mémoire de stockage interne de l'application. Essayez cet exemple:

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

Personnellement, je fais appel à des bibliothèques externes pour gérer la diffusion en continu dans un fichier. Celui-ci ne m'a pas encore échoué.

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

J'ai trop souvent perdu des données avec une commande d'écriture échouée. Je me suis donc appuyée sur des bibliothèques bien connues et testées pour mon IO).

Si les fichiers sont volumineux, vous pouvez également envisager d’exécuter le IO en arrière-plan ou d’utiliser des rappels.

Si vous utilisez déjà des variables d'environnement, il peut s'agir d'un problème d'autorisations. Découvrez la réponse de Justin Fiedler ci-dessous.

32
Garret

Pour l'API 23+, vous devez demander les autorisations de lecture/écriture, même si elles figurent 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" />
123
Justin Fiedler

Dans mon cas, je me suis trompé de cas

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

Android.permission doit être en minuscule, et d’une manière ou d’une autre, la chaîne entière était en majuscule dans notre source.

6
Graham Perks

J'ai aussi fait face au même problème. Après beaucoup de travail, j'ai trouvé ce qui n'allait pas dans mon cas. Mon appareil était connecté à l'ordinateur via un câble USB. Il existe différents types de connexions USB, tels que Stockage de masse, Périphérique multimédia (MTP), Appareil photo (PTP), etc. Mon type de connexion était - "Stockage de masse", ce qui posait problème. Lorsque j'ai changé le type de connexion, le problème a été résolu.

Rappelez-vous toujours lors de l'accès au système de fichiers sur Android périphérique: -

NE PAS CONNECTER COMME STOCK DE MASSE à l'ordinateur/pc.

5
ninad.sonje

Tout d'abord donner ou vérifier les autorisations comme

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

Si ces deux autorisations sont correctes, vérifiez que le format de vos flux de sortie est correct.

Exemple:

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

Dans mon cas, il s'agissait d'un problème d'autorisations. Le problème est que sur un appareil avec Android 4.0.4 j'ai accès au fichier sans erreur ni exception. Et sur un appareil avec Android 5.1, il a échoué avec ACCESS exception (ouverture a échoué: EACCES (autorisation refusée)). Gérée avec l'ajout de l'option suivante pour autoriser le fichier manifeste:

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

Je suppose donc que c'est la différence entre la gestion des autorisations dans les versions de système d'exploitation qui est à l'origine des échecs.

2
Anton Vaysberg

J'ai rencontré le même problème et j'ai constaté que je devais demander les autorisations au moment de l'exécution, même si je l'avais déclaré dans le manifeste. Tout comme indiqué dans la réponse de Justin Fiedler.

La documentation officielle à ce sujet se trouve ici: https://developer.Android.com/training/permissions/requesting.html

Mon implémentation est légèrement différente de la réponse de Justin Fiedler selon laquelle il implémentait également la méthode onRequestPermissionsResult du fragment v4 pour gérer la réponse à la demande de permission.

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
            }
        }
    }
}
2
Alex Bin Zhao

Dans mon cas, j'ai utilisé l'option Android:isolatedProcess="true" pour un service dans le AndroidManifest.xml.

Dès que je l'ai enlevé, l'erreur a disparu ...

1
Dirk

Ciblage des applications Android Q par défaut reçoit une vue filtrée du 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>

En savoir plus à ce sujet ici: https://developer.Android.com/preview/privacy/scoped-storage

1
Uriel Frankel

J'ai le même problème, mais parfois, le problème le plus difficile obtient une réponse simple.

Je revérifie les permissions manifestes et WAS_NOT n'écrit pas la permision honte de moi !!!

1
San Juan

Aussi j'ai trouvé résoudre pour mon chemin.

Avant le lancement de l'application, j'ai accordé la racine à File-Explorer et je n'ai pas désactivé l'autorisation d'écriture/de lecture lorsque vous quittez l'application.

Mon application ne peut pas utiliser de mémoire externe alors que je n'ai pas restauré l'appareil pour réinitialiser toutes les autorisations.

1
kaftanati

Si les clients utilisent Android 6.0, Android ajouté new modèle d'autorisation) pour (Marshmallow).

Astuce: Si vous ciblez la version 22 ou une version ultérieure, votre application demandera toutes les autorisations au moment de l'installation, comme elle le ferait pour tout périphérique utilisant un système d'exploitation sous Marshmallow.

0
Nourdine Alouane

Dans mon cas, le problème était que la configuration WIFI statique était en conflit avec un autre appareil utilisant la même adresse IP.

0
lloyd