95 votes

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

Samsung Galaxy S3 a une face externe sa fente de la carte SD, qui est monté à l' /mnt/extSdCard.

Ma question est: comment obtenir ce chemin par quelque chose comme Environment.getExternalStorageDirectory()? Ce sera le retour de mnt/sdcard, et je ne trouve pas API pour la carte SD externe. (Ou amovibles de stockage USB sur certaines tablettes)

Merci!!!!

59voto

Gnathonic Points 393

J'ai une variation sur une solution que j'ai trouvé ici

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;
}

La méthode originale a été testé et a travaillé avec

  • Huawei X3 (stock)
  • Galaxy S2 (stock)
  • Galaxy S3 (stock)

Je ne suis pas sûr de la version d'android sur quand ils ont été testés.

J'ai testé ma version modifiée, avec

  • Moto Xoom 4.1.2 (stock)
  • Galaxy Nexus (cyanogenmod 10) à l'aide d'un câble d'otg
  • HTC Incredible (cyanogenmod 7.2) cette retourné à la fois interne et externe. Cet appareil est un peu excentrique en interne va en grande partie inutilisé getExternalStorage() renvoie un chemin d'accès à la carte sd à la place.

et de quelques-uns des périphériques de stockage qui utilisent une carte sd comme leur principale de stockage

  • HTC G1 (cyanogenmod 6.1)
  • HTC G1 (stock)
  • HTC Vision/G2 (stock)

À l'exception de l'Incroyable tous ces appareils n'ont retourné leur stockage amovible. Il ya probablement quelques contrôles supplémentaires, je devrais faire, mais c'est au moins un peu mieux que toute solution que j'ai trouvé jusqu'à présent.

54voto

Dmitriy Lozenko Points 159

J'ai trouvé plus de moyen fiable pour obtenir les chemins de toutes les Cartes SD dans le système. Cela fonctionne sur toutes les versions d'Android et les voies du retour à tous les stockages (inclure émulé).

Fonctionne correctement sur tous mes appareils.

P. S.: Basé sur le code source de l'Environnement de la classe.

private static final Pattern DIR_SEPORATOR = Pattern.compile("/");

/**
 * Raturns all available SD-Cards in the system (include emulated)
 *
 * Warning: Hack! Based on Android source code of version 4.3 (API 18)
 * Because there is no standart way to get it.
 * TODO: Test on future Android versions 4.4+
 *
 * @return paths to all available SD-Cards in the system (include emulated)
 */
public static String[] getStorageDirectories()
{
    // Final set of paths
    final Set<String> rv = new HashSet<String>();
    // Primary physical SD-CARD (not emulated)
    final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");
    // All Secondary SD-CARDs (all exclude primary) separated by ":"
    final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
    // Primary emulated SD-CARD
    final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");
    if(TextUtils.isEmpty(rawEmulatedStorageTarget))
    {
        // Device has physical external storage; use plain paths.
        if(TextUtils.isEmpty(rawExternalStorage))
        {
            // EXTERNAL_STORAGE undefined; falling back to default.
            rv.add("/storage/sdcard0");
        }
        else
        {
            rv.add(rawExternalStorage);
        }
    }
    else
    {
        // Device has emulated storage; external storage paths should have
        // userId burned into them.
        final String rawUserId;
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
        {
            rawUserId = "";
        }
        else
        {
            final String path = Environment.getExternalStorageDirectory().getAbsolutePath();
            final String[] folders = DIR_SEPORATOR.split(path);
            final String lastFolder = folders[folders.length - 1];
            boolean isDigit = false;
            try
            {
                Integer.valueOf(lastFolder);
                isDigit = true;
            }
            catch(NumberFormatException ignored)
            {
            }
            rawUserId = isDigit ? lastFolder : "";
        }
        // /storage/emulated/0[1,2,...]
        if(TextUtils.isEmpty(rawUserId))
        {
            rv.add(rawEmulatedStorageTarget);
        }
        else
        {
            rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);
        }
    }
    // Add all secondary storages
    if(!TextUtils.isEmpty(rawSecondaryStoragesStr))
    {
        // All Secondary SD-CARDs splited into array
        final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
        Collections.addAll(rv, rawSecondaryStorages);
    }
    return rv.toArray(new String[rv.size()]);
}

32voto

FabianCook Points 5075

Je suppose que l'utilisation de la carte sd externe, vous devez utiliser ce:

new File("/mnt/external_sd/")

OU

new File("/mnt/extSdCard/")

dans votre cas...

en remplacer d' Environment.getExternalStorageDirectory()

Fonctionne pour moi. Vous devriez vérifier ce qui est dans le répertoire mnt première et de travailler à partir de là..


Vous devez utiliser un certain type de méthode de sélection pour choisir carte sd à utiliser:

File storageDir = new File("/mnt/");
if(storageDir.isDirectory()){
    String[] dirList = storageDir.list();
    //TODO some type of selecton method?
}

15voto

Paolo Rovelli Points 892

Afin de récupérer tous les Stockages Externes (qu'elles sont les cartes SD ou interne non amovible de stockages), vous pouvez utiliser le code suivant:

final String state = Environment.getExternalStorageState();

if ( Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) ) {  // we can read the External Storage...           
    //Retrieve the primary External Storage:
    final File primaryExternalStorage = Environment.getExternalStorageDirectory();

    //Retrieve the External Storages root directory:
    final String externalStorageRootDir;
    if ( (externalStorageRootDir = primaryExternalStorage.getParent()) == null ) {  // no parent...
        Log.d(TAG, "External Storage: " + primaryExternalStorage + "\n");
    }
    else {
        final File externalStorageRoot = new File( externalStorageRootDir );
        final File[] files = externalStorageRoot.listFiles();

        for ( final File file : files ) {
            if ( file.isDirectory() && file.canRead() && (file.listFiles().length > 0) ) {  // it is a real directory (not a USB drive)...
                Log.d(TAG, "External Storage: " + file.getAbsolutePath() + "\n");
            }
        }
    }
}

Alternativement, vous pouvez utiliser le Système.la fonction getenv("EXTERNAL_STORAGE") pour récupérer la primaire de Stockage Externe répertoire (par exemple "/storage/sdcard0") et du Système.la fonction getenv("SECONDARY_STORAGE") de recherchez la liste de tous les annuaires secondaires (par exemple, "/storage/extSdCard:/stockage/UsbDriveA:/stockage/UsbDriveB"). Rappelez-vous que, dans ce cas également, vous pouvez filtrer la liste des annuaires secondaires afin d'exclure les lecteurs USB.

Dans tous les cas, veuillez noter que l'utilisation codée en dur des chemins est toujours une mauvaise approche (spécialement lors de chaque fabricant peut modifier à mesure que le plaisir).

13voto

Jeff Sharkey Points 275

Bonne nouvelle! Dans 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 Context.getExternalCacheDirs() méthodes peut retourner plusieurs chemins d'accès, y compris à la fois primaire et secondaire des appareils. Vous pouvez ensuite effectuer une itération sur eux et de 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 soutien-v4 bibliothèque.

Notez également que si vous êtes seulement intéressés par l'utilisation de répertoires retourné par Context, vous n'avez plus besoin de l' READ_ ou WRITE_EXTERNAL_STORAGE des autorisations. À l'avenir, vous aurez toujours accès en lecture/écriture à ces répertoires sans les autorisations nécessaires.

Les applications peuvent aussi continuer à travailler sur des appareils plus anciens à la fin de l'lifing leur demande d'autorisation comme ceci:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X