web-dev-qa-db-fra.com

Android Open Répertoire de stockage externe (sdcard) pour stocker le fichier

Je veux ouvrir le chemin du répertoire de stockage externe pour enregistrer le fichier par programme. J'ai essayé, mais je n'ai pas réussi à obtenir le chemin de la carte SD . Comment puis-je procéder? Y a-t-il une solution pour cela ??

private File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "");

ou

private File path = new File(Environment.getExternalStorageDirectory() + "");

J'ai essayé d'obtenir le chemin par dessus les deux méthodes mais les deux pointent vers la mémoire interne.

Lorsque nous ouvrons la mémoire de stockage si sdcard est valide, il apparaîtra comme ci-dessous -enter image description here

stockage de l'appareil et carte mémoire SD.

Je veux obtenir le chemin de mémoire sd par le codage . J'ai donné des autorisations dans le manifeste-

    <uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission Android:name="Android.permission.STORAGE" />
    <uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />
34
yuva ツ

J'avais eu exactement le même problème!

Pour obtenir la carte SD interne, vous pouvez utiliser

String extStore = System.getenv("EXTERNAL_STORAGE");
File f_exts = new File(extStore);

Pour obtenir la carte SD externe, vous pouvez utiliser

String secStore = System.getenv("SECONDARY_STORAGE");
File f_secs = new File(secStore);

Sur l'exécution du code

 extStore = "/storage/emulated/legacy"
 secStore = "/storage/extSdCarcd"

marche parfaitement!

60
Rijul Gupta

Le stockage interne est appelé "stockage externe" dans l'API.

Comme mentionné dans le Environnement documentation

Remarque: ne soyez pas dérouté par le mot "externe" ici. Ce répertoire peut être mieux pensé comme média/stockage partagé. Il s'agit d'un système de fichiers pouvant contenir une quantité relativement importante de données et partagé entre toutes les applications (ne pas appliquer les autorisations). Il s’agit généralement d’une carte SD, mais elle peut également être implémentée comme stockage intégré dans un périphérique distinct du stockage interne protégé et peut être montée en tant que système de fichiers sur un ordinateur.

Pour savoir si "Environment.getExternalStorageDirectory ()" a effectivement renvoyé physiquement un stockage interne ou externe, appelez Environment.isExternalStorageEmulated (). Si c'est émulé, c'est interne. Sur les nouveaux périphériques dotés d'un stockage interne et d'un emplacement pour carte mémoire, Environment.getExternalStorageDirectory () renvoie toujours le stockage interne. Sur les appareils plus anciens qui ont uniquement une carte SD en tant qu'option de stockage sur support, la carte SD sera toujours renvoyée.

Il n’existe aucun moyen de récupérer tous les stockages à l’aide de l’API Android actuelle.

J'ai créé un assistant basé sur la méthode de Vitaliy Polchuk dans la réponse ci-dessous

Comment puis-je obtenir la liste du stockage externe monté sur un périphérique Android

REMARQUE: le démarrage du stockage secondaire KitKat est accessible uniquement en tant que READ-ONLY, vous pouvez vérifier la possibilité d'écriture en utilisant la méthode suivante

/**
 * Checks whether the StorageVolume is read-only
 * 
 * @param volume
 *            StorageVolume to check
 * @return true, if volume is mounted read-only
 */
public static boolean isReadOnly(@NonNull final StorageVolume volume) {
    if (volume.mFile.equals(Environment.getExternalStorageDirectory())) {
        // is a primary storage, check mounted state by Environment
        return Android.os.Environment.getExternalStorageState().equals(
                Android.os.Environment.MEDIA_MOUNTED_READ_ONLY);
    } else {
        if (volume.getType() == Type.USB) {
            return volume.isReadOnly();
        }
        //is not a USB storagem so it's read-only if it's mounted read-only or if it's a KitKat device
        return volume.isReadOnly() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat;
    }
}

Classe StorageHelper

import Java.io.BufferedReader;
import Java.io.File;
import Java.io.FileNotFoundException;
import Java.io.FileReader;
import Java.io.IOException;
import Java.util.ArrayList;
import Java.util.HashMap;
import Java.util.List;
import Java.util.Map;
import Java.util.Map.Entry;
import Java.util.StringTokenizer;

import Android.os.Environment;

public final class StorageHelper {

    //private static final String TAG = "StorageHelper";

    private StorageHelper() {
    }

    private static final String STORAGES_ROOT;

    static {
        final String primaryStoragePath = Environment.getExternalStorageDirectory()
                .getAbsolutePath();
        final int index = primaryStoragePath.indexOf(File.separatorChar, 1);
        if (index != -1) {
            STORAGES_ROOT = primaryStoragePath.substring(0, index + 1);
        } else {
            STORAGES_ROOT = File.separator;
        }
    }

    private static final String[] AVOIDED_DEVICES = new String[] {
        "rootfs", "tmpfs", "dvpts", "proc", "sysfs", "none"
    };

    private static final String[] AVOIDED_DIRECTORIES = new String[] {
        "obb", "asec"
    };

    private static final String[] DISALLOWED_FILESYSTEMS = new String[] {
        "tmpfs", "rootfs", "romfs", "devpts", "sysfs", "proc", "cgroup", "debugfs"
    };

    /**
     * Returns a list of mounted {@link StorageVolume}s Returned list always
     * includes a {@link StorageVolume} for
     * {@link Environment#getExternalStorageDirectory()}
     * 
     * @param includeUsb
     *            if true, will include USB storages
     * @return list of mounted {@link StorageVolume}s
     */
    public static List<StorageVolume> getStorages(final boolean includeUsb) {
        final Map<String, List<StorageVolume>> deviceVolumeMap = new HashMap<String, List<StorageVolume>>();

        // this approach considers that all storages are mounted in the same non-root directory
        if (!STORAGES_ROOT.equals(File.separator)) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader("/proc/mounts"));
                String line;
                while ((line = reader.readLine()) != null) {
                    // Log.d(TAG, line);
                    final StringTokenizer tokens = new StringTokenizer(line, " ");

                    final String device = tokens.nextToken();
                    // skipped devices that are not sdcard for sure
                    if (arrayContains(AVOIDED_DEVICES, device)) {
                        continue;
                    }

                    // should be mounted in the same directory to which
                    // the primary external storage was mounted
                    final String path = tokens.nextToken();
                    if (!path.startsWith(STORAGES_ROOT)) {
                        continue;
                    }

                    // skip directories that indicate tha volume is not a storage volume
                    if (pathContainsDir(path, AVOIDED_DIRECTORIES)) {
                        continue;
                    }

                    final String fileSystem = tokens.nextToken();
                    // don't add ones with non-supported filesystems
                    if (arrayContains(DISALLOWED_FILESYSTEMS, fileSystem)) {
                        continue;
                    }

                    final File file = new File(path);
                    // skip volumes that are not accessible
                    if (!file.canRead() || !file.canExecute()) {
                        continue;
                    }

                    List<StorageVolume> volumes = deviceVolumeMap.get(device);
                    if (volumes == null) {
                        volumes = new ArrayList<StorageVolume>(3);
                        deviceVolumeMap.put(device, volumes);
                    }

                    final StorageVolume volume = new StorageVolume(device, file, fileSystem);
                    final StringTokenizer flags = new StringTokenizer(tokens.nextToken(), ",");
                    while (flags.hasMoreTokens()) {
                        final String token = flags.nextToken();
                        if (token.equals("rw")) {
                            volume.mReadOnly = false;
                            break;
                        } else if (token.equals("ro")) {
                            volume.mReadOnly = true;
                            break;
                        }
                    }
                    volumes.add(volume);
                }

            } catch (IOException ex) {
                ex.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException ex) {
                        // ignored
                    }
                }
            }
        }

        // remove volumes that are the same devices
        boolean primaryStorageIncluded = false;
        final File externalStorage = Environment.getExternalStorageDirectory();
        final List<StorageVolume> volumeList = new ArrayList<StorageVolume>();
        for (final Entry<String, List<StorageVolume>> entry : deviceVolumeMap.entrySet()) {
            final List<StorageVolume> volumes = entry.getValue();
            if (volumes.size() == 1) {
                // go ahead and add
                final StorageVolume v = volumes.get(0);
                final boolean isPrimaryStorage = v.file.equals(externalStorage);
                primaryStorageIncluded |= isPrimaryStorage;
                setTypeAndAdd(volumeList, v, includeUsb, isPrimaryStorage);
                continue;
            }
            final int volumesLength = volumes.size();
            for (int i = 0; i < volumesLength; i++) {
                final StorageVolume v = volumes.get(i);
                if (v.file.equals(externalStorage)) {
                    primaryStorageIncluded = true;
                    // add as external storage and continue
                    setTypeAndAdd(volumeList, v, includeUsb, true);
                    break;
                }
                // if that was the last one and it's not the default external
                // storage then add it as is
                if (i == volumesLength - 1) {
                    setTypeAndAdd(volumeList, v, includeUsb, false);
                }
            }
        }
        // add primary storage if it was not found
        if (!primaryStorageIncluded) {
            final StorageVolume defaultExternalStorage = new StorageVolume("", externalStorage, "UNKNOWN");
            defaultExternalStorage.mEmulated = Environment.isExternalStorageEmulated();
            defaultExternalStorage.mType =
                    defaultExternalStorage.mEmulated ? StorageVolume.Type.INTERNAL
                            : StorageVolume.Type.EXTERNAL;
            defaultExternalStorage.mRemovable = Environment.isExternalStorageRemovable();
            defaultExternalStorage.mReadOnly =
                    Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
            volumeList.add(0, defaultExternalStorage);
        }
        return volumeList;
    }

    /**
     * Sets {@link StorageVolume.Type}, removable and emulated flags and adds to
     * volumeList
     * 
     * @param volumeList
     *            List to add volume to
     * @param v
     *            volume to add to list
     * @param includeUsb
     *            if false, volume with type {@link StorageVolume.Type#USB} will
     *            not be added
     * @param asFirstItem
     *            if true, adds the volume at the beginning of the volumeList
     */
    private static void setTypeAndAdd(final List<StorageVolume> volumeList,
            final StorageVolume v,
            final boolean includeUsb,
            final boolean asFirstItem) {
        final StorageVolume.Type type = resolveType(v);
        if (includeUsb || type != StorageVolume.Type.USB) {
            v.mType = type;
            if (v.file.equals(Environment.getExternalStorageDirectory())) {
                v.mRemovable = Environment.isExternalStorageRemovable();
            } else {
                v.mRemovable = type != StorageVolume.Type.INTERNAL;
            }
            v.mEmulated = type == StorageVolume.Type.INTERNAL;
            if (asFirstItem) {
                volumeList.add(0, v);
            } else {
                volumeList.add(v);
            }
        }
    }

    /**
     * Resolved {@link StorageVolume} type
     * 
     * @param v
     *            {@link StorageVolume} to resolve type for
     * @return {@link StorageVolume} type
     */
    private static StorageVolume.Type resolveType(final StorageVolume v) {
        if (v.file.equals(Environment.getExternalStorageDirectory())
                && Environment.isExternalStorageEmulated()) {
            return StorageVolume.Type.INTERNAL;
        } else if (containsIgnoreCase(v.file.getAbsolutePath(), "usb")) {
            return StorageVolume.Type.USB;
        } else {
            return StorageVolume.Type.EXTERNAL;
        }
    }

    /**
     * Checks whether the array contains object
     * 
     * @param array
     *            Array to check
     * @param object
     *            Object to find
     * @return true, if the given array contains the object
     */
    private static <T> boolean arrayContains(T[] array, T object) {
        for (final T item : array) {
            if (item.equals(object)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks whether the path contains one of the directories
     * 
     * For example, if path is /one/two, it returns true input is "one" or
     * "two". Will return false if the input is one of "one/two", "/one" or
     * "/two"
     * 
     * @param path
     *            path to check for a directory
     * @param dirs
     *            directories to find
     * @return true, if the path contains one of the directories
     */
    private static boolean pathContainsDir(final String path, final String[] dirs) {
        final StringTokenizer tokens = new StringTokenizer(path, File.separator);
        while (tokens.hasMoreElements()) {
            final String next = tokens.nextToken();
            for (final String dir : dirs) {
                if (next.equals(dir)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Checks ifString contains a search String irrespective of case, handling.
     * Case-insensitivity is defined as by
     * {@link String#equalsIgnoreCase(String)}.
     * 
     * @param str
     *            the String to check, may be null
     * @param searchStr
     *            the String to find, may be null
     * @return true if the String contains the search String irrespective of
     *         case or false if not or {@code null} string input
     */
    public static boolean containsIgnoreCase(final String str, final String searchStr) {
        if (str == null || searchStr == null) {
            return false;
        }
        final int len = searchStr.length();
        final int max = str.length() - len;
        for (int i = 0; i <= max; i++) {
            if (str.regionMatches(true, i, searchStr, 0, len)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Represents storage volume information
     */
    public static final class StorageVolume {

        /**
         * Represents {@link StorageVolume} type
         */
        public enum Type {
            /**
             * Device built-in internal storage. Probably points to
             * {@link Environment#getExternalStorageDirectory()}
             */
            INTERNAL,

            /**
             * External storage. Probably removable, if no other
             * {@link StorageVolume} of type {@link #INTERNAL} is returned by
             * {@link StorageHelper#getStorages(boolean)}, this might be
             * pointing to {@link Environment#getExternalStorageDirectory()}
             */
            EXTERNAL,

            /**
             * Removable usb storage
             */
            USB
        }

        /**
         * Device name
         */
        public final String device;

        /**
         * Points to mount point of this device
         */
        public final File file;

        /**
         * File system of this device
         */
        public final String fileSystem;

        /**
         * if true, the storage is mounted as read-only
         */
        private boolean mReadOnly;

        /**
         * If true, the storage is removable
         */
        private boolean mRemovable;

        /**
         * If true, the storage is emulated
         */
        private boolean mEmulated;

        /**
         * Type of this storage
         */
        private Type mType;

        StorageVolume(String device, File file, String fileSystem) {
            this.device = device;
            this.file = file;
            this.fileSystem = fileSystem;
        }

        /**
         * Returns type of this storage
         * 
         * @return Type of this storage
         */
        public Type getType() {
            return mType;
        }

        /**
         * Returns true if this storage is removable
         * 
         * @return true if this storage is removable
         */
        public boolean isRemovable() {
            return mRemovable;
        }

        /**
         * Returns true if this storage is emulated
         * 
         * @return true if this storage is emulated
         */
        public boolean isEmulated() {
            return mEmulated;
        }

        /**
         * Returns true if this storage is mounted as read-only
         * 
         * @return true if this storage is mounted as read-only
         */
        public boolean isReadOnly() {
            return mReadOnly;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((file == null) ? 0 : file.hashCode());
            return result;
        }

        /**
         * Returns true if the other object is StorageHelper and it's
         * {@link #file} matches this one's
         * 
         * @see Object#equals(Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final StorageVolume other = (StorageVolume) obj;
            if (file == null) {
                return other.file == null;
            }
            return file.equals(other.file);
        }

        @Override
        public String toString() {
            return file.getAbsolutePath() + (mReadOnly ? " ro " : " rw ") + mType + (mRemovable ? " R " : "")
                    + (mEmulated ? " E " : "") + fileSystem;
        }
    }
}
18

espérons que cela a fonctionné pour vous:

File yourFile = new File(Environment.getExternalStorageDirectory(), "textarabics.txt");

Cela vous donnera le chemin sdcard:

File path = Environment.getExternalStorageDirectory();

Essaye ça:

String pathName = "/mnt/";

ou essayez ceci:

String pathName = "/storage/";
4
Farhan Shah

Complétant rijul gupta réponse:

String strSDCardPath = System.getenv("SECONDARY_STORAGE");

    if ((strSDCardPath == null) || (strSDCardPath.length() == 0)) {
        strSDCardPath = System.getenv("EXTERNAL_SDCARD_STORAGE");
    }

    //If may get a full path that is not the right one, even if we don't have the SD Card there. 
    //We just need the "/mnt/extSdCard/" i.e and check if it's writable
    if(strSDCardPath != null) {
        if (strSDCardPath.contains(":")) {
            strSDCardPath = strSDCardPath.substring(0, strSDCardPath.indexOf(":"));
        }
        File externalFilePath = new File(strSDCardPath);

        if (externalFilePath.exists() && externalFilePath.canWrite()){
            //do what you need here
        }
    }
3
Alexandre

en prenant la réponse de @ rijul, cela ne fonctionne pas dans les versions Marshmallow et au-dessus:

       //for pre-Marshmallow versions
       String path = System.getenv("SECONDARY_STORAGE");

       // For Marshmallow, use getExternalCacheDirs() instead of System.getenv("SECONDARY_STORAGE")
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
           File[] externalCacheDirs = mContext.getExternalCacheDirs();
           for (File file : externalCacheDirs) {
               if (Environment.isExternalStorageRemovable(file)) {
                   // Path is in format /storage.../Android....
                   // Get everything before /Android
                   path = file.getPath().split("/Android")[0];
                   break;
               }
           }
       }


        // Android avd emulator doesn't support this variable name so using other one
        if ((null == path) || (path.length() == 0))
            path = Environment.getExternalStorageDirectory().getAbsolutePath();
2
Shubham

Je veux ouvrir le chemin du répertoire de stockage externe pour enregistrer le fichier par programme.J’ai essayé, mais je n’obtiens pas le chemin sdcard. Comment puis-je faire Est-ce qu'il y a une solution pour ça?

Pour stocker vos fichiers d'application sur la carte SD, vous devriez utiliser la méthode File[] getExternalFilesDirs (String type) dans la classe Context. En général, le deuxième chemin renvoyé serait le chemin de stockage de la carte microSD (le cas échéant).

Sur mon téléphone, le deuxième chemin renvoyé était /storage/sdcard1/Android/data/your.application.package.appname/files après avoir passé null comme argument à getExternalFilesDirs (String type). Mais le chemin peut varier sur différents téléphones, différentes versions d'Android.

File getExternalStorageDirectory () et File getExternalStoragePublicDirectory (String type) dans la classe Environment peuvent renvoyer un répertoire de carte SD ou un répertoire de mémoire interne en fonction du modèle de votre téléphone et de la version du système d'exploitation Android. 

Parce que selon Guide Android officiel stockage externe peut être

support de stockage amovible (tel qu'une carte SD) ou un .__ interne. stockage (non amovible).

La terminologie de stockage interne et externe selon Google/le document officiel Android est très différente de ce que nous pensons. 

0
AnV

oui, cela peut fonctionner dans KitKat.

au-dessus de KitKat +, il ira dans la mémoire de stockage interne: chemins comme (stockage/émulé/0).

réfléchissez comment l’application Xender donne la permission d’écrire sur une carte SD externe.

Donc, heureusement, dans Android 5.0 et les versions ultérieures, il existe une nouvelle méthode officielle permettant aux applications d'écrire sur la carte SD externe. Les applications doivent demander à l'utilisateur d'autoriser l'accès en écriture à un dossier de la carte SD. Ils ouvrent une boîte de dialogue de sélection de dossier système. L'utilisateur doit naviguer dans ce dossier spécifique et le sélectionner.

pour plus de détails, veuillez consulter https://metactrl.com/docs/sdcard-on-Lollipop/

0
Muhammed Haris