Façon universelle d'écrire à la carte SD externe sur Android

Dans mon application, j'ai besoin de stocker beaucoup d'images dans la mémoire de l'appareil. Ces fichiers ont tendance à remplir le stockage de périphérique, et je veux permettre aux utilisateurs de choisir une carte SD externe comme dossier de destination.

j'ai lu partout que 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 pas le stockage externe , mais les applications de gestionnaire de fichiers parviennent à écrire à SD externe sur toutes les versions Android.

Quelle est la meilleure façon d'accorder l'accès en lecture/écriture à une carte SD externe sur différents niveaux D'API (Pre-KitKat, KitKat, Lollipop+)?

"151950920 mise à jour" Update 1

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

HashSet<String> extDirs = getStorageDirectories();
for(String 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'ai une erreur d'accès, essayé 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.access0(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
62
demandé sur albodelu 2016-10-16 12:51:35

8 réponses

courte réponse.

ContextCompat.getExternalFilesDirs résout l'erreur d'accès lorsque vous n'avez pas besoin de partager des fichiers.

le mode de partage sécurisé est d'utiliser un fournisseur de contenu ou le nouveau cadre D'accès au stockage .


résumé.

il n'y a pas de voie universelle à écrire à la carte SD externe sur Android en raison de changements continus :

  • Pre-KitKat: plateforme officielle Android n'a pas pris en charge les cartes SD, sauf exceptions.

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

  • Lollipop: ajout D'API pour permettre aux applications de demander l'accès à des dossiers appartenant à d'autres fournisseurs.

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

Basé sur Doomsknight la réponse de et mine , et Dave Smith et : 1 , 2 , 3 :


1. Permissions.

Vous pouvez accorder l'accès en lecture/écriture à la carte SD externe sur le différentes api niveaux ( API23+ au moment de l'exécution ).

Depuis KitKat, autorisations pas nécessaire si vous utilisez l'application des répertoires spécifiques, nécessaire dans le cas contraire:

Avec Kitkat vos chances pour une "solution complète" sans enracinement sont à peu près zéro: le projet Android a certainement foiré ici. Aucune application n'a accès à 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 de médias: vous ne pouvez pas retag / re-organiser votre collection de médias plus longtemps, que ces applications ne peut pas écrire.
  • applications office: à peu près le même

Le seul endroit 3 rd les applications party sont autorisées à écrire sur votre les cartes externes sont "leurs propres répertoires" (i.e. /sdcard/Android/data/<package_name_of_the_app> ).

les seuls moyens de vraiment correctif qui nécessitent soit le fabricant (certains d'entre eux fixe il, par exemple Huawei avec leur mise à jour Kitkat pour le P6) – ou root... (l'explication D'Izzy continue ici)


2. à propos de la solution universelle.

le histoire dit qu'il n'y a pas façon universelle d'écrire à la carte SD externe mais continue...

Ce fait est démontrée par ces exemples de stockage externe configurations pour les appareils .

L'accès au stockage externe est protégé par divers Android autorisation. À partir de Android 1.0, l'accès en écriture est protégé avec le WRITE_EXTERNAL_STORAGE autorisation . À partir de Android 4.1, lire l'accès est protégé avec la permission READ_EXTERNAL_STORAGE .

à partir de Android 4.4, le propriétaire, le groupe et les modes de fichiers sur les périphériques de stockage externes sont maintenant synthétisés à partir du répertoire structure. Cela permet aux applications de gérer leur forfait spécifique répertoires de stockage externe sans exiger qu'ils détiennent le large WRITE_EXTERNAL_STORAGE autorisation. Par exemple, l'application du paquet nom com.example.foo peut maintenant accéder librement Android/data/com.example.foo/ sur les dispositifs de stockage externes sans autorisation. Ces permissions synthétisées sont accomplies par emballer des périphériques de stockage bruts dans un démon fusible.

Android 6.0 introduit un nouveau droits d'exécution modèle où les applications demande de capacités nécessaires à l'exécution. Parce que le nouveau modèle inclut les permissions READ/WRITE_EXTERNAL_STORAGE , la plate-forme doit accorder dynamiquement l'accès au stockage sans tuer ou redémarrage des applications déjà en cours d'exécution. Il le fait en maintenant trois vues distinctes de tous les dispositifs de stockage montés:

  • / mnt/runtime / default s'affiche aux applications sans stockage spécial autorisation...
  • /mnt/exécution/de lecture est indiqué pour les applications avec READ_EXTERNAL_STORAGE
  • / mnt / runtime / write s'affiche aux applications avec WRITE_EXTERNAL_STORAGE

3. à propos de votre mise à jour 1.

j'utiliserais les répertoires spécifiques aux applications pour éviter la publication de votre question mise à jour et ContextCompat.getExternalFilesDirs() en utilisant documentation getExternalFilesDir comme référence.

améliorer la heuristiques pour déterminer ce qui représente les supports amovibles basés sur les différents niveaux d'api comme android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT

rappelez-vous que Android 6.0 prend en charge les appareils de stockage portables et les applications tierces doivent passer par le cadre D'accès au stockage . Vos appareils HTC10 et Bouclier K1 sont probablement API 23.

Votre journal indique permission denied (accès refusé "l'exception 1519380920" accès /mnt/media_rw , comme ce correctif pour API 19+:

<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
<group gid="sdcard_r" />
<group gid="sdcard_rw" />
<group gid="media_rw" /> // this line is added via root in the link to fix it.
</permission>

Je ne l'ai jamais essayé donc je ne peux pas partager le code mais je voudrais éviter le for essayer d'écrire sur tous les répertoires retournés et chercher le meilleur répertoire de stockage disponible à écrire en fonction de l'espace restant .

peut-être alternative de Gizm0 à votre méthode getStorageDirectories() c'est un bon point de départ.

ContextCompat.getExternalFilesDirs résout la question si vous n'avez pas besoin de l'accès à d'autres dossiers .


4. Demande d'autorisation dans le manifeste (Api < 23) et à l'exécution (Api >= 23).

ajouter le code suivant à votre AndroidManifest.xml et lire obtenir l'accès au stockage externe

afin de ... d'écrire des fichiers sur le stockage externe, votre application doit acquérir. .. système autorisations:

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

si vous avez besoin des deux..., vous avez besoin de demander seulement la permission WRITE_EXTERNAL_STORAGE .

ignorez la note suivante en raison de bogues, mais essayez d'utiliser ContextCompat.getExternalFilesDirs() :

Note: en commençant par Android 4.4, ces permissions ne sont pas nécessaires si vous lisez ou écrivez seulement des fichiers qui sont privés à votre application. Pour plus d'info..., voir sauvegarder des fichiers qui sont app-privé .

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

Demander des autorisations lors de l'exécution si l'API de niveau 23+ et lire Demander des Autorisations au Moment de l'Exécution

à partir de Android 6.0 (API niveau 23), les utilisateurs accordent des permissions à applications pendant que l'application est en cours d'exécution, pas quand ils installent l'application ... ou de mise à jour de l'application ... l'utilisateur peut révoquer les autorisations.

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

5. Avant à KitKat essayer d'utiliser Doomsknight méthode 1, Méthode 2 autrement.

Lire Mark Murphy explication du et recommandé Dianne Hackborn et Dave Smith

  • Jusqu'à Android 4.4, il n'y avait aucun soutien officiel pour amovible médias sous Android, à partir de KitKat, le concept de stockage externe "primaire" et "secondaire" émerge dans L'API FMW.
  • les applications antérieures ne font que s'appuyer sur L'indexation MediaStore, la livraison avec le matériel ou examiner les points de montage et appliquer quelques heuristiques pour déterminer ce qui représente supports amovibles.
  • depuis Android 4.2, Il ya eu une demande de Google pour les fabricants d'appareils à verrouiller les supports amovibles pour la sécurité (multi-utilisateurs de soutien) et de nouveaux tests ont été ajoutés à la rubrique 4.4.
  • depuis KiKat getExternalFilesDirs() et d'autres méthodes ont été ajoutées pour retourner un chemin utilisable sur tous les volumes de stockage disponibles (Le premier article retourné est le volume principal).
  • le tableau ci-dessous indique ce qu'un développeur pourrait essayer de faire et comment KitKat répondra: enter image description here

avant L'essai de KitKat pour utiliser Doomsknight méthode 1 ou de lire cette réponse par Gnathonic ou gist :

public static HashSet<String> getExternalMounts() {
    final HashSet<String> out = new HashSet<String>();
    String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
    String 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 String(buffer);
        }
        is.close();
    } catch (final Exception e) {
        e.printStackTrace();
    }

    // parse output
    final String[] lines = s.split("\n");
    for (String line : lines) {
        if (!line.toLowerCase(Locale.US).contains("asec")) {
            if (line.matches(reg)) {
                String[] parts = line.split(" ");
                for (String part : parts) {
                    if (part.startsWith("/"))
                        if (!part.toLowerCase(Locale.US).contains("vold"))
                            out.add(part);
                }
            }
        }
    }
    return out;
}

lire aussi explication de Paolo Rovelli et essayer d'utiliser solution de Jeff Sharkey depuis KitKat:

à KitKat il y a maintenant une API publique pour interagir avec ces secondaires périphériques de stockage partagés.

le nouveau Context.getExternalFilesDirs() et Les méthodes Context.getExternalCacheDirs() peuvent retourner plusieurs chemins, y compris les dispositifs primaires et secondaires.

vous pouvez alors itérer sur eux et vérifier Environment.getStorageState() et File.getFreeSpace() afin de déterminer le meilleur endroit pour stocker vos fichiers.

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


6. Lollipop a également introduit des changements et la classe DocumentFile helper.

getStorageState ajouté dans API 19, déprécié dans API 21, utiliser getExternalStorageState(File)

voici un grand tutoriel pour interagir avec L'accès au stockage Cadre à KitKat.

interagissant 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 DRS de stockage externe.

"15194060920 Limités D'Accès Au Répertoire Dans Android 7.0, les applications peuvent utiliser de nouveaux API pour demander l'accès à des stockage externe répertoires, y compris les répertoires sur supports amovibles tels que les cartes SD...

pour de plus amples renseignements, voir la section formation sur L'accès aux répertoires .


8. Android O des changements.

à partir de Android O , le Le cadre d'accès au stockage permet documents personnalisés les fournisseurs de de créer des descripteurs de fichiers seekable pour les fichiers résidant dans une zone distante source de données...

Autorisations , avant Android O , si une application a demandé une permission à l'exécution et la permission a été accordée, le système a également accordé à tort l'application le reste des permissions qui appartenaient à la même l'autorisation du groupe, et qui ont été enregistrés dans le manifeste.

pour applications ciblant Android O , ce comportement a été corrigé. L'application est accordée uniquement les autorisations qu'il a explicitement demandé. Cependant, une fois que l'utilisateur accorde une autorisation à l'application, tous les les demandes d'autorisations dans ce groupe d'autorisations sont automatiquement accorder.

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 à l'intérieur du stockage flash interne, mais pas la carte SD?

Diff entre getExternalFilesDir et getExternalStorageDirectory()

pourquoi getExternalFilesDirs() ne fonctionne pas sur certains appareils?

Comment utiliser la nouvelle carte SD accès API présentée pour Android 5.0 (Lollipop)

l'Écriture de carte SD externe dans Android 5.0 et au-dessus de

Android Carte SD de l'Autorisation d'Écriture à l'aide de SAF (Accès au Stockage-Cadre)

SAFFAQ: L'Accès au Stockage-Cadre FAQ


10. bogues et problèmes liés.

Bug: sur Android 6, lorsque vous utilisez getExternalFilesDirs, il ne vous permettra pas de créer de nouveaux fichiers dans ses résultats

L'écriture dans le répertoire retourné par getExternalCacheDir () sur Lollipop échoue sans permission d'écriture

84
répondu albodelu 2018-01-09 20:19:48

je crois qu'il y a deux méthodes pour y parvenir:

MÉTHODE 1: ( PAS le travail 6.0 et au-dessus, en raison de modifications des autorisations)

j'utilise cette méthode depuis des années sur de nombreuses versions de périphériques sans problème. le crédit est dû à la source originale, car ce n'est pas moi qui l'ai écrit.

Il sera de retour tout monté médias (y compris Real SD Cards) dans une liste d'emplacements de répertoire de chaînes. Avec la liste, vous pouvez alors demander à l'utilisateur l'emplacement où enregistrer, etc.

vous pouvez l'appeler comme suit:

 HashSet<String> extDirs = getStorageDirectories();

méthode:

/**
 * Returns all the possible SDCard directories
 */
public static HashSet<String> getStorageDirectories() {
    final HashSet<String> out = new HashSet<String>();
    String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
    String 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 String(buffer);
        }
        is.close();
    } catch (final Exception e) {
        e.printStackTrace();
    }

    // parse output
    final String[] lines = s.split("\n");
    for (String line : lines) {
        if (!line.toLowerCase().contains("asec")) {
            if (line.matches(reg)) {
                String[] parts = line.split(" ");
                for (String part : parts) {
                    if (part.startsWith("/"))
                        if (!part.toLowerCase().contains("vold"))
                            out.add(part);
                }
            }
        }
    }
    return out;
}

méthode 2:

utiliser la bibliothèque de soutien v4

import android.support.v4.content.ContextCompat;

il suffit d'appeler ce qui suit pour obtenir une liste de File emplacements de stockage.

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

les emplacements diffèrent cependant dans l'utilisation.

renvoie les chemins absolus vers les répertoires spécifiques à l'application sur tous les les périphériques de stockage externes où l'application peut placer des fichiers persistant il possède. Ces fichiers sont internes à l'application, et généralement pas visible pour l'utilisateur en tant que média.

les dispositifs de stockage externes retournés ici sont considérés comme faisant partie intégrante le dispositif, y compris le stockage externe émulé et les médias physiques les fentes, telles que les cartes SD dans un compartiment de batterie. Le retour de chemins ne comprend pas les dispositifs transitoires, tels que les lecteurs flash USB.

une application peut stocker des données sur tout ou partie des appareils retournés. Pour exemple, une application peut choisir de stocker de gros fichiers sur l'appareil avec le la plupart de l'espace disponible

Plus D'Information on ContextCompat

ce sont comme des fichiers spécifiques à une application. Caché des autres applications.

9
répondu Doomsknight 2016-11-10 15:57:52

juste une autre réponse. Cette réponse montre seulement 5.0+ parce que je crois que la réponse de Doomknight posté ici est la meilleure façon de faire pour Android 4.4 et ci-dessous.

ceci est affiché à l'origine ici ( y a-t-il un moyen d'obtenir la taille de 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 comme un 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.toString());
                    }
                }
            }
        }
    } else {
        // do one of many old methods
        // I believe Doomsknight's method is the best option here
    }

    return externalStorage;
}

Note: je ne reçois que le "premier" carte SD externe cependant vous pouvez la modifier et retourner ArrayList<File> au lieu de File et laisser la boucle continuer au lieu d'appeler break après que le premier est trouvé.

2
répondu ᴛʜᴇᴘᴀᴛᴇʟ 2017-05-23 12:34:47

en plus de toutes les autres bonnes réponses, je pourrais ajouter un peu plus à cette question afin qu'elle puisse donner une couverture plus large pour les lecteurs. Dans ma réponse ici, j'utiliserais 2 ressources comptables pour présenter le stockage externe.

La première ressource est de Android Programmation, Le Big Nerd Ranch Guide de la 2e édition de , chapitre 16, page 294.

le livre décrit les méthodes de base et externe fichier et répertoire. Je vais essayer de faire un résumé de ce qui pourrait être pertinente à votre question.

la partie suivante du livre:

Stockage Externe

votre photo a besoin de plus qu'une place sur l'écran. Les photos grand format sont trop grandes pour coller à l'intérieur d'un Base de données SQLite, beaucoup moins un Intent . Ils auront besoin d'un endroit pour vivre dans votre système de fichiers. Normalement, vous les mettriez dans votre entrepôt privé. Rappelons que vous avez utilisé votre stockage privé pour sauvegarder votre base de données SQLite. Avec des méthodes comme Context.getFileStreamPath(String) et Context.getFilesDir() , vous pouvez faire la même chose avec les fichiers ordinaires, trop (qui vivent dans une subfolder adjacent aux bases de données subfolder your SQLite database lives in)

de Base de fichier et de répertoire des méthodes de Contexte

| Method                                                                                |
|---------------------------------------------------------------------------------------|
|File etFilesDir()                                                                      |
| - Returns a handle to the directory for private application files.                    |
|                                                                                       |
|FileInputStream openFileInput(String name)                                             |
| - Opens an existing file for input (relative to the files directory).                 |
|                                                                                       |
|FileOutputStream openFileOutput(String name, int mode)                                 |
| - Opens a file for output, possibly creating it (relative to the files directory).    |
|                                                                                       |
|File getDir(String name, int mode)                                                     |
| - Gets (and possibly creates) a subdirectory within the files directory.              |
|                                                                                       |
|String[] fileList()                                                                    |
| - Gets a list of file names in the main files directory, such as for use with         |
|   openFileInput(String).                                                              |
|                                                                                       |
|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 seul votre application doit utiliser, ces méthodes sont exactement ce que vous avez besoin d'.

par contre, si vous avez besoin d'une autre application pour écrire ces fichiers, vous n'avez pas de chance: alors que Il ya un Context.MODE_WORLD_READABLE drapeau que vous pouvez passer à openFileOutput(String, int) , il est dépréciée, et pas complètement fiable dans ses effets sur les nouveaux appareils. Si vous stockez des fichiers à partager avec d'autres applications ou la réception de fichiers à partir d'autres applications (fichiers comme des images stockées), vous avez besoin de les stocker sur stockage externe à la place.

Il existe deux types de stockage externe: primaire, et tout le reste. Tous les appareils Android ont à moins un emplacement pour le stockage externe: l'emplacement principal, qui est situé dans le dossier renvoyé par Environment.getExternalStorageDirectory() . C'est peut-être une carte SD, mais aujourd'hui c'est plus souvent intégré dans l'appareil lui-même. Certains appareils peuvent avoir un stockage externe supplémentaire. Que tomberait sous " tout le reste."

contexte fournit pas mal de méthodes pour obtenir à l'extérieur de stockage, aussi. Ces méthodes fournissent facile les moyens d'obtenir à votre stockage externe primaire, et en quelque sorte-des moyens faciles à obtenir à tout le reste. Tout ces méthodes stockent des fichiers dans des endroits accessibles au public, aussi, soyez prudent avec eux.

méthodes de fichiers externes et de répertoires dans 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(String)                                                       |
| - Returns a handle to a folder on primary external storage in which to store regular  |
|   files. If you pass in a type String, 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(String)                                                    |
| - Same as getExternalFilesDir(String), 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 appareils utilisent une carte SD amovible pour de stockage externe. Dans la pratique, cela est rarement un problème, parce que presque tous les appareils modernes ont un stockage interne non amovible pour leur stockage "externe". Il ne vaut donc pas la peine d'aller à des longueurs extrêmes pour en tenir compte. Mais nous avons recommandé d'inclure un code simple pour se prémunir contre cette possibilité, ce que vous ferez dans un instant.

autorisation de stockage externe

en général, vous avez besoin d'une permission pour écrire ou lire de stockage externe. Les Permissions sont des valeurs de chaîne bien connues que vous mettez dans votre manifeste en utilisant la balise <uses-permission> . Ils disent à Androïde que vous voulez faire quelque chose pour lequel Androïde veut que vous demandiez la permission.

ici, Android s'attend à ce que vous demandez la permission parce qu'il veut imposer une certaine responsabilité. Vous dites à Android que vous avez besoin d'accéder au stockage externe, et Android va ensuite dire à l'utilisateur que c'est l'une des choses que votre application fait quand ils essaient de l'installer. De cette façon, personne n'est surpris lorsque vous commencez à sauvegarder des choses sur leur carte SD.

dans Android 4.4, KitKat, ils ont assoupli cette restriction. Depuis Context.getExternalFilesDir(String) renvoie un dossier qui est spécifique à votre application, il est logique que vous voulez être en mesure de lire et d'écrire des fichiers qui y vivent. Donc sur Android 4.4 (API 19) et plus, vous n'avez pas besoin de cette permission pour ce dossier. (Mais vous avez encore besoin pour d'autres types de stockage externe.)

ajouter une ligne à votre manifeste qui demande la permission de lire le stockage externe, mais seulement jusqu'à la liste API 16.5 demander la permission de stockage externe ( AndroidManifest.xml )

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.bignerdranch.android.criminalintent" >
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
         android:maxSdkVersion="18" />

l'attribut maxSdkVersion fait en sorte que votre application ne demande cette permission que sur les versions D'Android qui sont plus anciennes que API 19, Android KitKat. Notez que vous ne demandez qu'à lire le stockage externe. Il y a aussi une permission WRITE_EXTERNAL_STORAGE , mais vous n'avez pas besoin il. Vous n'écrirez rien au stockage externe: l'application caméra le fera pour vous

la deuxième ressource est ce lien lisez tout, mais vous pouvez aussi sauter à en utilisant le stockage externe section.

référence:

plus d'informations:

Avertissement: Ce l'information a été tirée de Android Programming: The Big Nerd Ranch Guide avec la permission des auteurs. Pour plus d'informations sur ce livre ou pour acheter un exemplaire, veuillez visiter bignerdranch.com.

2
répondu maytham-ɯɐɥʇʎɐɯ 2018-02-09 10:00:02

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 montage" externes " disponibles qui, selon ma connaissance, fonctionne sur de nombreux appareils différents.

essentiellement, il lit les points de montage disponibles, filtre ceux qui sont invalides, teste le reste s'ils sont accessibles et les ajoute si toutes les conditions sont remplies.

bien sûr, les permissions requises doivent être accordé avant que le code ne soit invoqué.

// Notice: FileSystemDevice is just my own wrapper class. Feel free to replace it with your own. 

private List<FileSystemDevice> getDevices() {

    List<FileSystemDevice> 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.
                            String 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;
}
0
répondu Václav Hodek 2017-10-30 23:20:08

Voici une façon de créer un nouveau fichier dans le stockage externe (SDCard si présent dans le périphérique ou le stockage externe du périphérique si non). Il suffit de remplacer "foldername" par le nom du dossier de destination désiré et "filename" par le nom du fichier que vous sauvegardez. Bien sûr, Ici vous pouvez voir comment enregistrer un fichier Générique, maintenant vous pouvez rechercher comment enregistrer des images peut-être ici ou quoi que ce soit dans un fichier.

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

cette commande également que fichier existe et ajoute un nombre à la fin du nom du nouveau fichier pour l'enregistrer.

Espère que cela aide!

EDIT: Désolé, j'ai oublié que vous devez demander <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> dans votre manifeste (ou par programme si vous préférez la guimauve)

-1
répondu Hugo 2017-05-23 12:10:42
 
`Log.d(TAG, System.getenv("SECONDARY_STORAGE"));`

sortie:

`D/MainActivity: /storage/extSdCard`

Travailler sur le Note 3 Android 5.0.

-2
répondu user2773829 2017-11-26 05:10:15

pour les versions sous Marshmallow vous pouvez directement donner les permissions dans le manifeste.

mais pour les appareils avec Marshmallow et au-dessus vous devez accorder les permissions sur le temps d'exécution.

en utilisant

Environment.getExternalStorageDirectory();

vous pouvez accéder directement à la carte SD externe (monté un) Espérons que cette aide.

-3
répondu Geet Choubey 2016-10-16 10:08:13