Manière universelle d’écrire sur une carte SD externe sur Android

Dans mon application, je dois stocker de nombreuses images dans le stockage de l’appareil. Ces fichiers ont tendance à remplir le stockage de l’appareil, et je veux permettre aux utilisateurs de pouvoir choisir une carte SD externe comme dossier de destination.

Je lis partout qu’Android ne permet pas aux utilisateurs d’écrire sur une carte SD externe, par carte SD, je veux dire la carte SD externe et montable et non le stockage externe , mais les applications de gestion de fichiers écrivent sur SD externe sur toutes les versions Android.

Quel est le meilleur moyen d’accorder un access en lecture / écriture à une carte SD externe à différents niveaux d’API (Pre-KitKat, KitKat, Lollipop +)?

Mise à jour 1

J’ai essayé la méthode 1 de la réponse de Doomknight, sans résultat: comme vous pouvez le voir, je vérifie les permissions à l’exécution avant d’essayer d’écrire sur SD:

HashSet extDirs = getStorageDirectories(); for(Ssortingng dir: extDirs) { Log.e("SD",dir); File f = new File(new File(dir),"TEST.TXT"); try { if(ActivityCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED) { f.createNewFile(); } } catch (IOException e) { e.printStackTrace(); } } 

Mais j’obtiens une erreur d’access, essayée sur deux appareils différents: HTC10 et Shield K1.

 10-22 14:52:57.329 30280-30280/? E/SD: /mnt/media_rw/F38E-14F8 10-22 14:52:57.329 30280-30280/? W/System.err: java.io.IOException: open failed: EACCES (Permission denied) 10-22 14:52:57.329 30280-30280/? W/System.err: at java.io.File.createNewFile(File.java:939) 10-22 14:52:57.329 30280-30280/? W/System.err: at com.myapp.activities.TestActivity.onResume(TestActivity.java:167) 10-22 14:52:57.329 30280-30280/? W/System.err: at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1326) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.Activity.performResume(Activity.java:6338) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3336) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3384) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2574) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.access$900(ActivityThread.java:150) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1399) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.os.Looper.loop(Looper.java:168) 10-22 14:52:57.330 30280-30280/? W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5885) 10-22 14:52:57.330 30280-30280/? W/System.err: at java.lang.reflect.Method.invoke(Native Method) 10-22 14:52:57.330 30280-30280/? W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:819) 10-22 14:52:57.330 30280-30280/? W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:709) 10-22 14:52:57.330 30280-30280/? W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied) 10-22 14:52:57.330 30280-30280/? W/System.err: at libcore.io.Posix.open(Native Method) 10-22 14:52:57.330 30280-30280/? W/System.err: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186) 10-22 14:52:57.330 30280-30280/? W/System.err: at java.io.File.createNewFile(File.java:932) 10-22 14:52:57.330 30280-30280/? W/System.err: ... 14 more 

Réponse courte.

ContextCompat.getExternalFilesDirs résout l’erreur d’access lorsque vous n’avez pas besoin de partager des fichiers.

La méthode sécurisée de partage consiste à utiliser un fournisseur de contenu ou le nouveau Storage Access Framework .


Résumé.

Il n’y a pas de moyen universel d’ écrire sur une carte SD externe sur Android en raison de changements continus :

  • Pre-KitKat: la plate-forme Android officielle ne supporte pas du tout les cartes SD sauf exceptions.

  • KitKat: a introduit des API qui permettent aux applications d’accéder aux fichiers des répertoires spécifiques aux applications sur les cartes SD.

  • Lollipop: ajout d’API pour permettre aux applications de demander l’access aux dossiers appartenant à d’autres fournisseurs.

  • Nougat: fourni une API simplifiée pour accéder aux répertoires de stockage externes communs.

Basé sur la réponse de Doomsknight et la mienne , et les articles de blog de Dave Smith et Mark Murphy: 1 , 2 , 3 :

  • Idéalement, utilisez Storage Access Framework et DocumentFile comme l’a souligné Jared Rummler . Ou:
  • Utilisez le chemin d’access spécifique à votre application /storage/extSdCard/Android/data/com.myapp.example/files .
  • Ajouter une autorisation en lecture / écriture pour manifester pour pre-KitKat, aucune autorisation requirejse ultérieurement pour ce chemin.
  • Essayez d’utiliser votre chemin d’application et les méthodes de Doomsknight en prenant en compte les cas KitKat et Samsung .
  • Filtrer et utiliser getStorageDirectories , votre chemin d’application et les permissions de lecture / écriture avant KitKat.
  • ContextCompat.getExternalFilesDirs depuis KitKat. Considérant les périphériques qui retournent en premier en interne.

1. Autorisations.

Vous pouvez accorder un access en lecture / écriture à une carte SD externe sur les différents niveaux de l’ API ( API23 + au moment de l’exécution ).

Depuis KitKat, les permissions ne sont pas nécessaires si vous utilisez des répertoires spécifiques à l’application, requirejs autrement:

Avec Kitkat, vos chances de trouver une “solution complète” sans enracinement sont quasiment nulles: le projet Android a définitivement échoué ici. Aucune application n’a un access complet à la carte SD externe:

  • gestionnaires de fichiers: vous ne pouvez pas les utiliser pour gérer votre carte SD externe. Dans la plupart des domaines, ils ne peuvent que lire mais pas écrire.
  • applications multimédia: vous ne pouvez plus retracer / réorganiser votre collection de médias, car ces applications ne peuvent pas y écrire.
  • applications de bureau: à peu près la même chose

Le seul endroit où les applications tierces sont autorisées à écrire sur votre carte externe sont “leurs propres répertoires” (c. /sdcard/Android/data/ d. /sdcard/Android/data/ ).

Les seuls moyens de résoudre ce problème nécessitent soit le fabricant (certains l’ont réparé, par exemple Huawei avec leur mise à jour Kitkat pour le P6) – soit le root … (l’explication d’Izzy continue ici)


2. À propos de la solution universelle.

L’ histoire dit qu’il n’y a pas de moyen universel d’écrire sur une carte SD externe mais continue …

Ce fait est démontré par ces exemples de configurations de stockage externe pour les périphériques .

L’access au stockage externe est protégé par diverses permissions Android. À partir d’Android 1.0, l’access en écriture est protégé par l’ autorisation WRITE_EXTERNAL_STORAGE . À partir d’Android 4.1, l’access en lecture est protégé avec l’autorisation READ_EXTERNAL_STORAGE .

À partir d’Android 4.4, le propriétaire, le groupe et les modes des fichiers sur les périphériques de stockage externes sont désormais synthétisés en fonction de la structure des répertoires. Cela permet aux applications de gérer leurs répertoires spécifiques aux packages sur un stockage externe sans nécessiter la permission WRITE_EXTERNAL_STORAGE . Par exemple, l’application avec le nom de package com.example.foo peut désormais accéder librement à Android/data/com.example.foo/ sur des périphériques de stockage externes sans autorisation. Ces permissions synthétisées sont obtenues en encapsulant des périphériques de stockage bruts dans un démon FUSE.

Android 6.0 introduit un nouveau modèle d’ permissions d’exécution dans lequel les applications demandent des fonctionnalités en cas de besoin au moment de l’exécution. Étant donné que le nouveau modèle inclut les permissions READ/WRITE_EXTERNAL_STORAGE , la plate-forme doit accorder de manière dynamic un access au stockage sans tuer ni redémarrer les applications déjà exécutées. Pour cela, trois vues distinctes de tous les périphériques de stockage montés sont disponibles:

  • / mnt / runtime / default est affiché pour les applications sans permissions de stockage spéciales …
  • / mnt / runtime / read est affiché pour les applications avec READ_EXTERNAL_STORAGE
  • / mnt / runtime / write est affiché aux applications avec WRITE_EXTERNAL_STORAGE

3. À propos de votre mise à jour 1.

Je voudrais utiliser des répertoires spécifiques à l’ application pour éviter le problème de votre question mise à jour et ContextCompat.getExternalFilesDirs() utilisant la documentation getExternalFilesDir comme référence.

Améliorez l’ heuristique pour déterminer ce que représentent les supports amovibles basés sur les différents niveaux d’api, tels que android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT

N’oubliez pas qu’Android 6.0 prend en charge les périphériques de stockage portables et que les applications tierces doivent passer par le Storage Access Framework . Vos appareils HTC10 et Shield K1 sont probablement des API 23.

Votre journal affiche une exception d’autorisation refusée accédant à /mnt/media_rw , comme cette correction pour API 19+:

     // this line is added via root in the link to fix it.  

Je ne l’ai jamais essayé pour que je ne puisse pas partager le code, mais j’éviterais de le faire for essayer d’écrire sur tous les répertoires renvoyés et de rechercher le meilleur répertoire de stockage disponible en fonction de l’espace restant .

Peut-être que l’alternative de getStorageDirectories() à votre méthode getStorageDirectories() est un bon sharepoint départ.

ContextCompat.getExternalFilesDirs résout le problème si vous n’avez pas besoin d’ accéder à d’autres dossiers .


4. Demander des permissions dans le manifeste (Api <23) et à l'exécution (Api> = 23).

Ajoutez le code suivant à votre AndroidManifest.xml et lisez Accès au stockage externe

Pour … écrire des fichiers sur le stockage externe, votre application doit acquérir … des permissions système:

     

Si vous avez besoin des deux …, vous devez demander uniquement l’autorisation WRITE_EXTERNAL_STORAGE .

Ignorez la note suivante à cause de bogues, mais essayez d’utiliser ContextCompat.getExternalFilesDirs() :

Remarque: à partir d’Android 4.4, ces permissions ne sont pas requirejses si vous lisez ou écrivez uniquement des fichiers privés sur votre application. Pour plus d’informations, reportez-vous à l’ enregistrement de fichiers app-private .

    

Demander des permissions à l’exécution si le niveau 23+ de l’API et lire les permissions de demande au moment de l’exécution

À partir d’Android 6.0 (niveau 23 de l’API), les utilisateurs accordent des permissions aux applications lorsque l’application est en cours d’exécution, et non lors de l’installation de l’application … ou de la mise à jour de l’application … l’utilisateur peut révoquer les permissions.

 // Assume thisActivity is the current activity int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE); 

5. Avant KitKat, essayez d’utiliser la méthode Doomsknight 1, méthode 2 sinon.

Lisez l’explication de Mark Murphy et recommandez celles de Dianne Hackborn et Dave Smith

  • Jusqu’à Android 4.4, il n’y avait pas de support officiel pour les supports amovibles sous Android. Depuis KitKat, le concept de stockage externe «primaire» et «secondaire» apparaît dans l’API FMW.
  • Les applications antérieures reposent uniquement sur l’indexation MediaStore, livrées avec le matériel ou examinent les points de assembly et appliquent des méthodes heuristiques pour déterminer ce qui représente les supports amovibles.
  • Depuis Android 4.2, Google a demandé aux fabricants d’appareils de verrouiller les supports amovibles pour la sécurité (support multi-utilisateurs) et de nouveaux tests ont été ajoutés dans 4.4.
  • Depuis KiKat getExternalFilesDirs() et d’autres méthodes ont été ajoutées pour renvoyer un chemin utilisable sur tous les volumes de stockage disponibles (le premier élément renvoyé est le volume principal).
  • Le tableau ci-dessous indique ce qu’un développeur peut essayer de faire et comment KitKat répondra: entrer la description de l'image ici

Avant KitKat, essayez d’utiliser la méthode Doomsknight 1 ou lisez cette réponse par Gnathonic ou Gist:

 public static HashSet getExternalMounts() { final HashSet out = new HashSet(); Ssortingng reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*"; Ssortingng s = ""; try { final Process process = new ProcessBuilder().command("mount") .redirectErrorStream(true).start(); process.waitFor(); final InputStream is = process.getInputStream(); final byte[] buffer = new byte[1024]; while (is.read(buffer) != -1) { s = s + new Ssortingng(buffer); } is.close(); } catch (final Exception e) { e.printStackTrace(); } // parse output final Ssortingng[] lines = s.split("\n"); for (Ssortingng line : lines) { if (!line.toLowerCase(Locale.US).contains("asec")) { if (line.matches(reg)) { Ssortingng[] parts = line.split(" "); for (Ssortingng part : parts) { if (part.startsWith("/")) if (!part.toLowerCase(Locale.US).contains("vold")) out.add(part); } } } } return out; } 

Lisez aussi l’explication de Paolo Rovelli et essayez d’utiliser la solution de Jeff Sharkey depuis KitKat:

Dans KitKat, il existe maintenant une API publique pour interagir avec ces périphériques de stockage partagés secondaires.

Les nouvelles Context.getExternalFilesDirs() et Context.getExternalCacheDirs() peuvent renvoyer plusieurs chemins, y compris des périphériques principaux et secondaires.

Vous pouvez ensuite les parcourir et vérifier Environment.getStorageState() et File.getFreeSpace() pour déterminer le meilleur emplacement pour stocker vos fichiers.

Ces méthodes sont également disponibles sur ContextCompat dans la bibliothèque support-v4.


6. Lollipop a également introduit des modifications et la classe d’assistance DocumentFile .

getStorageState Ajouté dans l’API 19, déconseillé dans l’API 21, utilisez getExternalStorageState(File)

Voici un excellent tutoriel pour interagir avec le Storage Access Framework dans KitKat.

L’interaction avec les nouvelles API dans Lollipop est très similaire (l’explication de Jeff Sharkey) .


7. Android 7.0 fournit une API simplifiée pour accéder aux répertoires de stockage externes.

Scoped Directory Access Dans Android 7.0, les applications peuvent utiliser de nouvelles API pour demander l’access à des répertoires de stockage externes spécifiques, notamment des répertoires sur des supports amovibles tels que des cartes SD …

Pour plus d’informations, consultez la formation Scoped Directory Access .


8. Android O change.

À partir d’Android O , Storage Access Framework permet aux fournisseurs de documents personnalisés de créer des descripteurs de fichiers recherchés pour les fichiers résidant dans une source de données distante …

Autorisations , avant Android O , si une application demandait une autorisation à l’exécution et que l’autorisation était accordée, le système accordait également de manière incorrecte à l’application le rest des permissions appartenant au même groupe d’permissions et enregistrées dans le manifeste.

Pour les applications ciblant Android O , ce comportement a été corrigé. L’application ne dispose que des permissions demandées explicitement. Toutefois, une fois que l’utilisateur accorde une autorisation à l’application, toutes les demandes ultérieures d’permissions dans ce groupe d’permissions sont automatiquement accordées.

Par exemple, READ_EXTERNAL_STORAGE et WRITE_EXTERNAL_STORAGE


9. Questions connexes et réponses recommandées.

Comment puis-je obtenir un chemin de carte SD externe pour Android 4.0+?

mkdir () fonctionne dans le stockage flash interne, mais pas sur la carte SD?

Diff entre getExternalFilesDir et getExternalStorageDirectory ()

Pourquoi getExternalFilesDirs () ne fonctionne pas sur certains périphériques?

Comment utiliser la nouvelle API d’access à la carte SD présentée pour Android 5.0 (Lollipop)

Écriture sur une carte SD externe sous Android 5.0 et supérieur

Autorisation d’écriture de carte SD Android à l’aide de SAF (Storage Access Framework)

SAFFAQ: la FAQ sur le Framework Storage Access


10. Bugs et problèmes liés.

Bug: Sous Android 6, lors de l’utilisation de getExternalFilesDirs, il ne vous laissera pas créer de nouveaux fichiers dans ses résultats

L’écriture dans le répertoire renvoyé par getExternalCacheDir () sur Lollipop échoue sans autorisation d’écriture

Je crois qu’il existe deux méthodes pour y parvenir:

MÉTHODE 1: (ne fonctionne pas sur 6.0 et supérieur, en raison de modifications d’autorisation)

J’utilise cette méthode depuis des années sur de nombreuses versions de périphérique sans problème. Le crédit est dû à la source originale, car ce n’est pas moi qui l’a écrit.

Il retournera tous les supports montés (y compris les cartes SD réelles) dans une liste d’emplacements de répertoires de chaînes. Avec la liste, vous pouvez alors demander à l’utilisateur où enregistrer, etc.

Vous pouvez l’appeler avec les éléments suivants:

  HashSet extDirs = getStorageDirectories(); 

Méthode:

 /** * Returns all the possible SDCard directories */ public static HashSet getStorageDirectories() { final HashSet out = new HashSet(); Ssortingng reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*"; Ssortingng s = ""; try { final Process process = new ProcessBuilder().command("mount") .redirectErrorStream(true).start(); process.waitFor(); final InputStream is = process.getInputStream(); final byte[] buffer = new byte[1024]; while (is.read(buffer) != -1) { s = s + new Ssortingng(buffer); } is.close(); } catch (final Exception e) { e.printStackTrace(); } // parse output final Ssortingng[] lines = s.split("\n"); for (Ssortingng line : lines) { if (!line.toLowerCase().contains("asec")) { if (line.matches(reg)) { Ssortingng[] parts = line.split(" "); for (Ssortingng part : parts) { if (part.startsWith("/")) if (!part.toLowerCase().contains("vold")) out.add(part); } } } } return out; } 

MÉTHODE 2:

Utiliser la bibliothèque de support v4

 import android.support.v4.content.ContextCompat; 

Il suffit d’appeler le suivant pour obtenir une liste des emplacements de stockage du File .

  File[] list = ContextCompat.getExternalFilesDirs(myContext, null); 

Les emplacements diffèrent cependant par l’utilisation.

Renvoie les chemins absolus vers les répertoires spécifiques à l’application sur tous les périphériques de stockage externes sur lesquels l’application peut placer des fichiers persistants qu’elle possède. Ces fichiers sont internes à l’application et ne sont généralement pas visibles par l’utilisateur en tant que support.

Les périphériques de stockage externes renvoyés ici sont considérés comme faisant partie intégrante du périphérique, y compris les emplacements de stockage physique et de stockage externe émulés, tels que les cartes SD dans un compartiment de batterie. Les chemins renvoyés n’incluent pas les périphériques transitoires, tels que les lecteurs flash USB.

Une application peut stocker des données sur tout ou partie des périphériques renvoyés. Par exemple, une application peut choisir de stocker des fichiers volumineux sur le périphérique avec le plus d’espace disponible.

Plus d’infos sur ContextCompat

Ils sont comme des fichiers spécifiques à l’application. Caché des autres applications.

Juste une autre réponse. Cette réponse montre seulement 5.0+ parce que je crois que la réponse de Doomknight affichée ici est la meilleure façon de faire pour Android 4.4 et les versions ultérieures.

Ceci est à l’origine posté ici ( y at-il un moyen d’obtenir la taille de la carte SD dans Android? ) Par moi pour obtenir la taille de la carte SD externe sur Android 5.0+

Pour obtenir la carte SD externe en tant que File :

 public File getExternalSdCard() { File externalStorage = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { File storage = new File("/storage"); if(storage.exists()) { File[] files = storage.listFiles(); for (File file : files) { if (file.exists()) { try { if (Environment.isExternalStorageRemovable(file)) { externalStorage = file; break; } } catch (Exception e) { Log.e("TAG", e.toSsortingng()); } } } } } else { // do one of many old methods // I believe Doomsknight's method is the best option here } return externalStorage; } 

Remarque: je ne reçois que la “première” carte SD externe, mais vous pouvez la modifier et renvoyer ArrayList au lieu de File et laisser la boucle continuer au lieu d’appeler break après la découverte du premier.

En plus de toutes les autres bonnes réponses, je pourrais append un peu plus à cette question pour qu’elle couvre plus largement les lecteurs. Dans ma réponse, j’utiliserais 2 ressources comptables pour présenter le stockage externe.

La première ressource provient de la programmation Android, The Big Nerd Ranch Guide, 2e édition , chapitre 16, page 294.

Le livre décrit les méthodes de fichiers et de répertoires de base et externes. Je vais essayer de faire un résumé de ce qui pourrait être pertinent pour votre question.

La partie suivante du livre:

Stockage externe

Votre photo nécessite plus qu’une place à l’écran. Les images en taille réelle sont trop grandes pour restr dans une firebase database SQLite, et encore moins une Intent . Ils auront besoin d’un endroit pour vivre sur le système de fichiers de votre appareil. Normalement, vous les placeriez dans votre espace de stockage privé. Rappelez-vous que vous avez utilisé votre stockage privé pour enregistrer votre firebase database SQLite. Avec des méthodes telles que Context.getFileStreamPath(Ssortingng) et Context.getFilesDir() , vous pouvez faire la même chose avec les fichiers normaux (qui vivront dans un sous-dossier adjacent au sous-dossier de bases de données dans lequel réside votre firebase database SQLite)

Méthodes de base de fichiers et de répertoires dans le contexte

 | Method | |---------------------------------------------------------------------------------------| |File etFilesDir() | | - Returns a handle to the directory for private application files. | | | |FileInputStream openFileInput(Ssortingng name) | | - Opens an existing file for input (relative to the files directory). | | | |FileOutputStream openFileOutput(Ssortingng name, int mode) | | - Opens a file for output, possibly creating it (relative to the files directory). | | | |File getDir(Ssortingng name, int mode) | | - Gets (and possibly creates) a subdirectory within the files directory. | | | |Ssortingng[] fileList() | | - Gets a list of file names in the main files directory, such as for use with | | openFileInput(Ssortingng). | | | |File getCacheDir() | | - Returns a handle to a directory you can use specifically for storing cache files. | | You should take care to keep this directory tidy and use as little space as possible| 

Si vous stockez des fichiers que seule votre application actuelle doit utiliser, ces méthodes sont exactement ce dont vous avez besoin.

D’un autre côté, si vous avez besoin d’une autre application pour écrire dans ces fichiers, vous n’avez pas de chance: alors qu’il existe un indicateur Context.MODE_WORLD_READABLE , vous pouvez le transmettre à openFileOutput(Ssortingng, int) . dans ses effets sur les nouveaux appareils. Si vous stockez des fichiers à partager avec d’autres applications ou que vous recevez des fichiers provenant d’autres applications (fichiers tels que des images stockées), vous devez les stocker dans un stockage externe.

Il existe deux types de stockage externe: primaire et tout le rest. Tous les appareils Android ont au moins un emplacement pour le stockage externe: l’emplacement principal, situé dans le dossier renvoyé par Environment.getExternalStorageDirectory() . Cela peut être une carte SD, mais de nos jours, elle est plus souvent intégrée à l’appareil lui-même. Certains périphériques peuvent avoir un stockage externe supplémentaire. Cela tomberait sous «tout le rest».

Le contexte fournit également plusieurs méthodes pour accéder au stockage externe. Ces méthodes fournissent des moyens simples pour accéder à votre stockage externe principal et des méthodes simples pour accéder à tout le rest. Toutes ces méthodes stockent également des fichiers dans des lieux accessibles au public, alors faites attention avec eux.

Méthodes externes de fichiers et de répertoires dans le contexte

 | Method | | --------------------------------------------------------------------------------------| |File getExternalCacheDir() | | - Returns a handle to a cache folder in primary external storage. Treat it like you do| | getCacheDir(), except a little more carefully. Android is even less likely to clean | | up this folder than the private storage one. | | | |File[] getExternalCacheDirs() | | - Returns cache folders for multiple external storage locations. | | | |File getExternalFilesDir(Ssortingng) | | - Returns a handle to a folder on primary external storage in which to store regular | | files. If you pass in a type Ssortingng, you can access a specific subfolder dedicated | | to a particular type of content. Type constants are defined in Environment, where | | they are prefixed with DIRECTORY_. | | For example, pictures go in Environment.DIRECTORY_PICTURES. | | | |File[] getExternalFilesDirs(Ssortingng) | | - Same as getExternalFilesDir(Ssortingng), but returns all possible file folders for the | | given type. | | | |File[] getExternalMediaDirs() | | - Returns handles to all the external folders Android makes available for storing | | media – pictures, movies, and music. What makes this different from calling | | getExternalFilesDir(Environment.DIRECTORY_PICTURES) is that the media scanner | | automatically scans this folder. The media scanner makes files available to | | applications that play music, or browse movies and photos, so anything that you | | put in a folder returned by getExternalMediaDirs() will automatically appear in | | those apps. | 

Techniquement, les dossiers externes fournis ci-dessus peuvent ne pas être disponibles, car certains périphériques utilisent une carte SD amovible pour le stockage externe. En pratique, cela pose rarement problème car presque tous les appareils modernes disposent d’un stockage interne non amovible pour leur stockage «externe». Donc, il ne vaut pas la peine d’aller à l’extrême pour en rendre compte. Mais nous vous recommandons d’inclure un code simple pour vous prémunir contre la possibilité que vous ferez dans un instant.

Autorisation de stockage externe

En général, vous avez besoin d’une autorisation pour écrire ou lire à partir d’un stockage externe. Les permissions sont des valeurs de chaîne bien connues que vous insérez dans votre manifeste à l’aide de la . Ils disent à Android que vous voulez faire quelque chose que Android veut que vous demandiez la permission.

Ici, Android s’attend à ce que vous demandiez la permission, car il veut imposer une certaine responsabilité. Vous dites à Android que vous devez accéder au stockage externe, et Android indiquera alors à l’utilisateur que c’est l’une des choses que votre application fait lorsqu’elle essaie de l’installer. De cette façon, personne n’est surpris lorsque vous commencez à enregistrer des éléments sur leur carte SD.

Dans Android 4.4, KitKat, ils ont assoupli cette ressortingction. Étant donné que Context.getExternalFilesDir(Ssortingng) renvoie un dossier spécifique à votre application, il est logique que vous souhaitiez pouvoir lire et écrire des fichiers qui y vivent. Donc, sur Android 4.4 (API 19) et plus, vous n’avez pas besoin de cette autorisation pour ce dossier. (Mais vous en avez toujours besoin pour d’autres types de stockage externe.)

Ajouter une ligne à votre manifeste qui demande l’autorisation de lire le stockage externe, mais uniquement jusqu’à API API Listing 16.5 Demander une autorisation de stockage externe ( AndroidManifest.xml )

   

L’atsortingbut maxSdkVersion fait en sorte que votre application demande uniquement cette autorisation sur les versions d’Android antérieures à l’API 19, Android KitKat. Notez que vous ne demandez que la lecture du stockage externe. Il existe également une autorisation WRITE_EXTERNAL_STORAGE , mais vous n’en avez pas besoin. Vous n’écrirez rien sur le stockage externe: L’application de l’appareil photo le fera pour vous

La deuxième ressource est ce lien tout lire, mais vous pouvez également passer à la section Utilisation du stockage externe .

Référence:

Plus de lecture:

Disclaimer: Cette information a été prise à partir de la programmation Android: The Big Nerd Ranch Guide avec la permission des auteurs. Pour plus d’informations sur ce livre ou pour en acheter un exemplaire, visitez le site bignerdranch.com.

Ce sujet est un peu ancien mais je cherchais une solution et après quelques recherches, je suis venu avec le code ci-dessous pour récupérer une liste de points de assembly “externes” disponibles qui, à ma connaissance, fonctionne sur de nombreux appareils différents.

Fondamentalement, il lit les points de assembly disponibles, filtre les points non valides, teste le rest s’ils sont accessibles et les ajoute si toutes les conditions sont remplies.

Bien entendu, les permissions requirejses doivent être accordées avant d’appeler le code.

 // Notice: FileSystemDevice is just my own wrapper class. Feel free to replace it with your own. private List getDevices() { List devices = new ArrayList<>(); // Add default external storage if available. File sdCardFromSystem = null; switch(Environment.getExternalStorageState()) { case Environment.MEDIA_MOUNTED: case Environment.MEDIA_MOUNTED_READ_ONLY: case Environment.MEDIA_SHARED: sdCardFromSystem = Environment.getExternalStorageDirectory(); break; } if (sdCardFromSystem != null) { devices.add(new FileSystemDevice(sdCardFromSystem)); } // Read /proc/mounts and add all mount points that are available // and are not "special". Also, check if the default external storage // is not contained inside the mount point. try { FileInputStream fs = new FileInputStream("/proc/mounts"); String mounts = IOUtils.toString(fs, "UTF-8"); for(String line : mounts.split("\n")) { String[] parts = line.split(" "); // parts[0] - mount type // parts[1] - mount point if (parts.length > 1) { try { // Skip "special" mount points and mount points that can be accessed // directly by Android's functions. if (parts[0].equals("proc")) { continue; } if (parts[0].equals("rootfs")) { continue; } if (parts[0].equals("devpts")) { continue; } if (parts[0].equals("none")) { continue; } if (parts[0].equals("sysfs")) { continue; } if (parts[0].equals("selinuxfs")) { continue; } if (parts[0].equals("debugfs")) { continue; } if (parts[0].equals("tmpfs")) { continue; } if (parts[1].equals(Environment.getRootDirectory().getAbsolutePath())) { continue; } if (parts[1].equals(Environment.getDataDirectory().getAbsolutePath())) { continue; } if (parts[1].equals(Environment.getExternalStorageDirectory().getAbsolutePath())) { continue; } // Verify that the mount point is accessible by listing its content. File file = new File(parts[1]); if (file.listFiles() != null) { try { // Get canonical path for case it's just symlink to another mount point. Ssortingng devPath = file.getCanonicalPath(); for(FileSystemDevice device : devices) { if (!devices.contains(devPath)) { devices.add(new FileSystemDevice(new File(devPath))); } } } catch (Exception e) { // Silently skip the exception as it can only occur if the mount point is not valid. e.printStackTrace(); } } } catch (Exception e) { // Silently skip the exception as it can only occur if the mount point is not valid. e.printStackTrace(); } } } fs.close(); } catch (FileNotFoundException e) { // Silently skip the exception as it can only occur if the /proc/mounts file is unavailable. // Possibly, another detection method can be called here. e.printStackTrace(); } catch (IOException e) { // Silently skip the exception as it can only occur if the /proc/mounts file is unavailable. // Possibly, another detection method can be called here. e.printStackTrace(); } return devices; } 

Voici un moyen de créer un nouveau fichier dans le stockage externe (si la carte SD est présente dans le périphérique ou le périphérique de stockage externe, sinon). Remplacez simplement “foldername” par le nom du dossier de destination souhaité et “filename” par le nom du fichier que vous enregistrez. Of course here you can see how to save a generic File, now you can search for how to save images maybe here or whatever in a file.

 try { File dir = new File(Environment.getExternalStorageDirectory() + "/foldername/"); if (!dir.exists()){ dir.mkdirs(); } File sdCardFile = new File(Environment.getExternalStorageDirectory() + "/foldername/" + fileName ); int num = 1; Ssortingng fileNameAux = fileName; while (sdCardFile.exists()){ fileNameAux = fileName+"_"+num; sdCardFile = new File(Environment.getExternalStorageDirectory() + "/foldername/" + fileNameAux); num++; } 

This also controls that file exists and adds a number in the end of the name of the new file to save it.

J’espère que cela aide!

EDIT: Sorry, i forgot you have to ask for in your manifest (or programatically if you prefer from Marshmallow)

 
`Log.d(TAG, System.getenv("SECONDARY_STORAGE"));`

sortie:

`D/MainActivity: /storage/extSdCard`

Working on Note 3 Android 5.0.

For versions below Marshmallow you can directly give the permissions in the manifest.

But for devices with Marshmallow and above you need to grant the permissions on run time.

En utilisant

 Environment.getExternalStorageDirectory(); 

you can directly access the External SD card (Mounted one) Hope this helps.