web-dev-qa-db-fra.com

java.io.FileNotFoundException (autorisation refusée) lors d'une tentative d'écriture sur la carte SD Android

J'essaie de sélectionner un fichier image de la galerie de photos et d'écrire sur la carte SD. Vous trouverez ci-dessous le code qui génère une exception. Il semble que cette exception soit générée lors de la tentative de création de FileOutputStream. J'ai la ligne suivante ajoutée au fichier manifeste imbriqué dans l'élément d'application. Je ne trouve pas de solution au problème:

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

public boolean saveSelectedImage( Uri selectedImage, int imageGroup,
        int imageNumber )
{
    boolean exception = false;
    InputStream input = null;
    OutputStream output = null;
    if( externalStorageIsWritable() )
    {
        try
        {
            ContentResolver content = ctx.getContentResolver();
            input = content.openInputStream( selectedImage );
            if(input != null) Log.v( CLASS_NAME, "Input Stream Opened successfully");
            File outFile = null;

            File root = Environment.getExternalStorageDirectory(  );
            if(root == null) Log.v(CLASS_NAME, "FAILED TO RETRIEVE DIRECTORY");
            else Log.v(CLASS_NAME, "ROOT DIRECTORY is:"+root.toString());

            output = new FileOutputStream( root+"/Image"+ imageGroup + "_" + imageNumber + ".png" );

            if(output != null) Log.e( CLASS_NAME, "Output Stream Opened successfully");
            //  output = new FileOutputStream
            // ("/sdcard/Image"+imageGroup+"_"+imageNumber+".png");

            byte[] buffer = new byte[1000];
            int bytesRead = 0;
            while ( ( bytesRead = input.read( buffer, 0, buffer.length ) ) >= 0 )
            {
                output.write( buffer, 0, buffer.length );
            }
        } catch ( Exception e )
        {

            Log.e( CLASS_NAME, "Exception occurred while moving image: ");
            e.printStackTrace();

            exception = true;
        } finally
        {
            // if(input != null)input.close();
            // if(output != null)output.close();
            // if (exception ) return false;
        }

        return true;
    } else
        return false;

}
17
joefischer1

Voici à quoi devrait ressembler votre fichier manifeste

 

<application Android:icon="@drawable/icon" Android:label="@string/app_name">
    <activity Android:name=".WriteCBTextToFileActivity"
              Android:label="@string/app_name">
        <intent-filter>
            <action Android:name="Android.intent.action.MAIN" />
            <category Android:name="Android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />

24
Saurabh

J'ai eu ce problème et les réponses ici n'ont pas résolu le problème, car j'avais commis une erreur assez stupide. 

Assurez-vous de donner une carte SD à votre émulateur Android ... J'avais laissé la taille de la carte SD vierge et, bien sûr, il n'a rien trouvé. En plus de cela, je spécifiais un répertoire à l'intérieur de ladite carte SD qui n'avait pas encore été créé, alors assurez-vous de considérer également ce cas.

(Vous pouvez modifier les paramètres de la carte SD d'un AVD en accédant au Gestionnaire de périphériques virtuels Android, en modifiant l'émulateur de votre choix et en entrant une valeur pour la taille de la carte SD.)

9
deluxxxe

Vous devez également vous assurer que le sous-système de stockage externe est dans le bon état. utilisez Environment.getExternalStorageState() et cherchez Environment.MEDIA_MOUNTED qui est le seul état sûr.

Il est également judicieux de limiter la gestion des exceptions à IOException autour de ces sections afin d'éviter de trop récupérer des problèmes spécifiques à l'IO, par exemple. support non monté.

Si vous avez besoin d'événements, il existe des intentions de diffusion (Intent.ACTION_MEDIA_xxx) avec les mêmes informations que vous pouvez vous inscrire avec IntentListener.

Notez également que le stockage externe peut être désactivé lorsque vous utilisez USB pour le débogage!

Lors du démarrage du périphérique, le stockage externe n’est pas disponible pendant une période prolongée. Si vous faites des choses dans les services au démarrage, c'est un problème.

En règle générale, votre application doit connaître l'état du stockage externe lors de son accès et gérer les cas d'indisponibilité ou de perte d'indisponibilité lors de l'accès.

7
escape-llc

Si les autorisations appropriées sont définies dans le manifeste, assurez-vous que votre appareil n'est pas en mode "Lecteur de disque" lors de la connexion à un PC. Changez-le en mode "Charge uniquement" et cela devrait fonctionner.

3
Dave_S

Notez qu'en plus de la réponse Saurabh, depuis l'API 23, vous devez demander des autorisations au moment de l'exécution.

Voir ici: https://developer.Android.com/training/permissions/requesting.html

Et la réponse de Justin Fiedler ici: https://stackoverflow.com/a/33288986/328059

En outre, j'ai eu plusieurs cas où, après avoir modifié les autorisations et réexécuté l'application à l'aide de l'exécution instantanée, les autorisations n'étaient pas mises à jour. Il est donc recommandé, après avoir modifié le manifeste, de désinstaller l'application du périphérique cible et de la reconstruire.

2
Nitay

Vous pouvez essayer avec:

String myPath=Environment.getExternalStorageDirectory()+"/Image"+ imageGroup + "_" + imageNumber + ".png";

File myFile = new File();      
input = new FileInputStream(myFile);
0
Dinh Nguu Nguyen

Essayez d’utiliser openFileOutput("filename") pour renvoyer un FileOutputStream au lieu de spécifier l’emplacement par vous-même. 

Consultez le doc ici

0
Timothy Leung