Come posso ottenere il percorso della scheda SD esterna per Android 4.0+?


93

Samsung Galaxy S3 ha uno slot per schede SD esterno, che è montato su /mnt/extSdCard.

Come posso ottenere questo percorso con qualcosa di simile Environment.getExternalStorageDirectory()?

Questo tornerà mnt/sdcarde non riesco a trovare l'API per la scheda SD esterna. (O un archivio USB rimovibile su alcuni tablet.)


Perché vuoi questo? È molto sconsigliabile su Android fare cose del genere. Forse, se condividi la tua motivazione, possiamo indicarti la migliore pratica per questo tipo di cose.
tardi

2
Quando l'utente cambia il proprio telefono, collega la scheda SD al nuovo telefono e sul primo telefono è / sdcard, sul secondo telefono è / mnt / extSdCard, tutto ciò che utilizza il percorso del file va in crash. Ho bisogno di generare un percorso reale dal suo percorso relativo.
Romulus Urakagi Ts'ai

Ora questo argomento è vecchio ma potrebbe essere d'aiuto. dovresti usare questo metodo. System.getenv (); vedere il progetto Environment3 per accedere a tutti gli archivi collegati al dispositivo. github.com/omidfaraji/Environment3
Omid Faraji


Ecco la mia soluzione che funziona fino a Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

Risposte:


58

Ho una variazione su una soluzione che ho trovato qui

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

Il metodo originale è stato testato e utilizzato

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

Non sono sicuro su quale versione di Android si trovassero quando sono stati testati.

Ho testato la mia versione modificata con

  • Moto Xoom 4.1.2 (di serie)
  • Galaxy Nexus (cyanogenmod 10) utilizzando un cavo otg
  • HTC Incredible (cyanogenmod 7.2) ha restituito sia l'interno che l'esterno. Questo dispositivo è un po 'strano in quanto il suo interno rimane in gran parte inutilizzato poiché getExternalStorage () restituisce invece un percorso alla sdcard.

e alcuni dispositivi di archiviazione singoli che utilizzano una scheda SD come memoria principale

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

Ad eccezione dell'Incredibile, tutti questi dispositivi restituivano solo la loro memoria rimovibile. Probabilmente ci sono alcuni controlli extra che dovrei fare, ma questo è almeno un po 'meglio di qualsiasi soluzione che ho trovato finora.


3
Penso che la tua soluzione fornirà un nome di cartella non valido se quella originale contiene lettere maiuscole come / mnt / SdCard
Eugene Popovich

1
Ho provato su alcuni dispositivi Motorola, Samsung e LG e ha funzionato perfettamente.
pepedeutico

2
@KhawarRaza, questo metodo ha smesso di funzionare a partire da kitkat. Usa il metodo di Dmitriy Lozenko, con questo come riserva se stai supportando dispositivi pre-ics.
Gnathonic

1
Funziona su HUAWEI Honor 3c. Grazie.
li2

2
questo sta restituendo / mnt invece di / storage su 4.0+ per me su un Galaxy Note 3
ono

54

Ho trovato un modo più affidabile per ottenere percorsi a tutte le SD-CARD nel sistema. Funziona su tutte le versioni di Android e restituisce i percorsi a tutti gli archivi (includi emulati).

Funziona correttamente su tutti i miei dispositivi.

PS: basato sul codice sorgente della classe Environment.

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()]);
}

5
Cosa doveva essere DIR_SEPORATOR?
cYrixmorten

1
@cYrixmorten è fornito in cima al codice .. è un Patternper/
Ankit Bansal

Qualcuno ha provato questa soluzione su Lolipop?
lenrok258

Ho provato questo metodo su lenovo P780 ma non funziona.
Satheesh Kumar

2
Funziona fino a Lollipop; non funziona su Marshmallow (Galaxy Tab A w / 6.0.1) dove System.getenv("SECONDARY_STORAGE")ritorna /storage/sdcard1. Quella posizione non esiste, ma la posizione effettiva è /storage/42CE-FD0A, dove 42CE-FD0A è il numero di serie del volume della partizione formattata.
DaveAlden

32

Immagino che per usare la sdcard esterna devi usare questo:

new File("/mnt/external_sd/")

O

new File("/mnt/extSdCard/")

nel tuo caso...

in sostituzione di Environment.getExternalStorageDirectory()

Per me va bene. Dovresti prima controllare cosa c'è nella directory mnt e lavorare da lì ..


È necessario utilizzare un metodo di selezione per scegliere quale scheda SD utilizzare:

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

1
In effetti, voglio un metodo piuttosto che un percorso hard-code, ma l'elenco / mnt / dovrebbe andare bene. Grazie.
Romulus Urakagi Ts'ai

Nessun problema. Avere un'opzione nelle impostazioni da cui si sceglie il percorso, quindi utilizzare il metodo per recuperarlo.
FabianCook

10
Purtroppo la scheda SD esterna potrebbe trovarsi in una cartella diversa da / mnt. Ad esempio, su Samsung GT-I9305 è / storage / extSdCard mentre la scheda SD incorporata ha il percorso / storage / sdcard0
iseeall

2
Bene, allora dovresti ottenere la posizione della scheda SD, quindi ottenere la sua directory principale.
FabianCook

Quale sarà il percorso della scheda SD esterna (per pendrive collegata a tablet tramite cavo OTG) per Android 4.0+?
osimer pothe

15

Per recuperare tutti gli Archivi Esterni (siano essi schede SD o archivi interni non rimovibili ), è possibile utilizzare il seguente codice:

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

In alternativa, potresti utilizzare System.getenv ("EXTERNAL_STORAGE") per recuperare la directory di archiviazione esterna primaria (ad esempio "/ storage / sdcard0" ) e System.getenv ("SECONDARY_STORAGE") per recuperare l'elenco di tutte le directory secondarie (ad esempio " / storage / extSdCard: / storage / UsbDriveA: / storage / UsbDriveB " ). Ricorda che, anche in questo caso, potresti voler filtrare la lista delle directory secondarie in modo da escludere le unità USB.

In ogni caso, tieni presente che l'utilizzo di percorsi hard-coded è sempre un cattivo approccio (specialmente quando ogni produttore può modificarlo a piacere).


System.getenv ("SECONDARY_STORAGE") NON ha funzionato per i dispositivi USB collegati tramite cavo OTG su Nexus 5 e Nexus 7.
Khawar Raza

Ecco la mia soluzione che funziona fino a Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

14

Stavo usando la soluzione di Dmitriy Lozenko fino a quando ho controllato un Asus Zenfone2 , Marshmallow 6.0.1 e la soluzione non funzionava. La soluzione non è riuscita durante l'ottenimento di EMULATED_STORAGE_TARGET , in particolare per il percorso microSD, ad esempio: / storage / F99C-10F4 / . Ho modificato il codice per ottenere i percorsi di root emulati direttamente dai percorsi dell'applicazione emulata con context.getExternalFilesDirs(null);e aggiungere percorsi fisici più noti specifici del modello di telefono .

Per semplificarci la vita, ho creato una biblioteca qui . Puoi usarlo tramite gradle, maven, sbt e leiningen build system.

Se ti piace la vecchia maniera, puoi anche copiare e incollare il file direttamente da qui , ma non saprai se ci sarà un aggiornamento in futuro senza controllarlo manualmente.

Se hai domande o suggerimenti, per favore fatemelo sapere


1
Non l'ho usato ampiamente, ma funziona bene per il mio problema.
David

1
Ottima soluzione! Una nota tuttavia: se la scheda SD viene rimossa quando l'applicazione è attiva, context.getExternalFilesDirs(null)verrà restituito nulluno dei file e ci sarà un'eccezione nel ciclo seguente. Suggerisco di aggiungere if (file == null) continue;come prima riga del ciclo.
Koger

1
@Koger grazie per il suggerimento, l'ho aggiunto e corretto un errore di battitura alla mia risposta
HendraWD

13

Buone notizie! In KitKat è ora disponibile un'API pubblica per interagire con questi dispositivi di archiviazione condivisi secondari.

I nuovi metodi Context.getExternalFilesDirs()e Context.getExternalCacheDirs()possono restituire più percorsi, inclusi i dispositivi primari e secondari. È quindi possibile iterare su di essi e controllare Environment.getStorageState()eFile.getFreeSpace() determinare il posto migliore in cui archiviare i file. Questi metodi sono disponibili anche ContextCompatnella libreria support-v4.

Nota anche che se sei interessato solo a utilizzare le directory restituite da Context, non hai più bisogno di READ_oWRITE_EXTERNAL_STORAGE autorizzazioni . In futuro, avrai sempre accesso in lettura / scrittura a queste directory senza autorizzazioni aggiuntive richieste.

Le app possono anche continuare a lavorare su dispositivi meno recenti terminando la loro richiesta di autorizzazione in questo modo:

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

Grazie. Ho creato del codice che segue quello che hai scritto e penso che funzioni bene nel trovare tutti i percorsi delle schede SD. Puoi dare un'occhiata? Qui: stackoverflow.com/a/27197248/878126. A proposito, non dovresti usare "getFreeSpace" perché in teoria, lo spazio libero può cambiare durante il runtime.
sviluppatore Android


10

Ho fatto quanto segue per avere accesso a tutte le schede SD esterne.

Con:

File primaryExtSd=Environment.getExternalStorageDirectory();

ottieni il percorso per l'SD esterno principale Quindi con:

File parentDir=new File(primaryExtSd.getParent());

si ottiene la directory principale della memoria esterna primaria, ed è anche la directory principale di tutte le sd esterne. Ora puoi elencare tutto lo spazio di archiviazione e selezionare quello che desideri.

Spero sia utile.


Questa dovrebbe essere la risposta accettata e grazie è utile.
Meanman

9

Ecco come ottengo l'elenco dei percorsi della scheda SD (esclusa la memoria esterna principale):

  /**
   * returns a list of all available sd cards paths, or null if not found.
   * 
   * @param includePrimaryExternalStorage set to true if you wish to also include the path of the primary external storage
   */
  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  public static List<String> getSdCardPaths(final Context context,final boolean includePrimaryExternalStorage)
    {
    final File[] externalCacheDirs=ContextCompat.getExternalCacheDirs(context);
    if(externalCacheDirs==null||externalCacheDirs.length==0)
      return null;
    if(externalCacheDirs.length==1)
      {
      if(externalCacheDirs[0]==null)
        return null;
      final String storageState=EnvironmentCompat.getStorageState(externalCacheDirs[0]);
      if(!Environment.MEDIA_MOUNTED.equals(storageState))
        return null;
      if(!includePrimaryExternalStorage&&VERSION.SDK_INT>=VERSION_CODES.HONEYCOMB&&Environment.isExternalStorageEmulated())
        return null;
      }
    final List<String> result=new ArrayList<>();
    if(includePrimaryExternalStorage||externalCacheDirs.length==1)
      result.add(getRootOfInnerSdCardFolder(externalCacheDirs[0]));
    for(int i=1;i<externalCacheDirs.length;++i)
      {
      final File file=externalCacheDirs[i];
      if(file==null)
        continue;
      final String storageState=EnvironmentCompat.getStorageState(file);
      if(Environment.MEDIA_MOUNTED.equals(storageState))
        result.add(getRootOfInnerSdCardFolder(externalCacheDirs[i]));
      }
    if(result.isEmpty())
      return null;
    return result;
    }

  /** Given any file/folder inside an sd card, this will return the path of the sd card */
  private static String getRootOfInnerSdCardFolder(File file)
    {
    if(file==null)
      return null;
    final long totalSpace=file.getTotalSpace();
    while(true)
      {
      final File parentFile=file.getParentFile();
      if(parentFile==null||parentFile.getTotalSpace()!=totalSpace||!parentFile.canRead())
        return file.getAbsolutePath();
      file=parentFile;
      }
    }

externalCacheDirs[0].getParentFile().getParentFile().getParentFile().getParentFile().getAbsolutePath()Questa è una ricetta per il disastro. Se lo stai facendo, potresti anche codificare il percorso che desideri poiché, se ottieni una directory della cache con qualcosa di diverso da 4 genitori, otterrai NullPointerException o il percorso sbagliato.
tardi

@rharter Correct. Risolto anche questo problema. Per favore guarda.
sviluppatore Android

La documentazione ( developer.android.com/reference/android/content/… ) dice "I dispositivi di archiviazione esterni restituiti qui sono considerati una parte permanente del dispositivo, inclusi sia l'archiviazione esterna emulata che gli slot per supporti fisici, come le schede SD in una batteria compartimento. I percorsi restituiti non includono dispositivi transitori, come unità flash USB. " Sembra che anche loro non includano slot per schede SD, ovvero i punti in cui è possibile rimuovere una scheda SD senza andare sotto la batteria. Difficile da dire, però.
LarsH

1
@ LarsH Beh, l'ho testato io stesso su SGS3 (e una vera scheda SD), quindi penso che dovrebbe funzionare anche su altri dispositivi.
sviluppatore Android

5

Grazie per gli indizi forniti da voi ragazzi, in particolare @SmartLemon, ho trovato la soluzione. Nel caso in cui qualcun altro ne abbia bisogno, metto qui la mia soluzione finale (per trovare la prima scheda SD esterna elencata):

public File getExternalSDCardDirectory()
{
    File innerDir = Environment.getExternalStorageDirectory();
    File rootDir = innerDir.getParentFile();
    File firstExtSdCard = innerDir ;
    File[] files = rootDir.listFiles();
    for (File file : files) {
        if (file.compareTo(innerDir) != 0) {
            firstExtSdCard = file;
            break;
        }
    }
    //Log.i("2", firstExtSdCard.getAbsolutePath().toString());
    return firstExtSdCard;
}

Se non è presente alcuna scheda SD esterna, restituisce la memoria a bordo. Lo userò se la sdcard non esiste, potrebbe essere necessario cambiarla.


1
questo lancio di null su Android versione 19. rootDir.listFiles () restituisce null. L'ho testato con Nexus 7, emulatore e Galaxy Note.
Manu Zi

3

fare riferimento al mio codice, spero sia utile per te:

    Runtime runtime = Runtime.getRuntime();
    Process proc = runtime.exec("mount");
    InputStream is = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(is);
    String line;
    String mount = new String();
    BufferedReader br = new BufferedReader(isr);
    while ((line = br.readLine()) != null) {
        if (line.contains("secure")) continue;
        if (line.contains("asec")) continue;

        if (line.contains("fat")) {//TF card
            String columns[] = line.split(" ");
            if (columns != null && columns.length > 1) {
                mount = mount.concat("*" + columns[1] + "\n");
            }
        } else if (line.contains("fuse")) {//internal storage
            String columns[] = line.split(" ");
            if (columns != null && columns.length > 1) {
                mount = mount.concat(columns[1] + "\n");
            }
        }
    }
    txtView.setText(mount);

2

In realtà in alcuni dispositivi il nome predefinito della scheda SD esterna viene visualizzato come extSdCarde per altri lo è sdcard1.

Questo frammento di codice aiuta a scoprire quel percorso esatto e aiuta a recuperare il percorso del dispositivo esterno.

String sdpath,sd1path,usbdiskpath,sd0path;    
        if(new File("/storage/extSdCard/").exists())
            {
               sdpath="/storage/extSdCard/";
               Log.i("Sd Cardext Path",sdpath);
            }
        if(new File("/storage/sdcard1/").exists())
         {
              sd1path="/storage/sdcard1/";
              Log.i("Sd Card1 Path",sd1path);
         }
        if(new File("/storage/usbcard1/").exists())
         {
              usbdiskpath="/storage/usbcard1/";
              Log.i("USB Path",usbdiskpath);
         }
        if(new File("/storage/sdcard0/").exists())
         {
              sd0path="/storage/sdcard0/";
              Log.i("Sd Card0 Path",sd0path);
         }

Questo mi ha aiutato immensamente.
Droid Chris

Ci sono alcuni dispositivi che utilizzano "/ storage / external_sd" (LG G3 KitKat), Marshmallow ha uno schema diverso, la memoria interna su Nexus 5X che utilizza Android 6.0 è "/ mnt / sdcard" e la scheda SD esterna si trova in "/ storage / XXXX-XXXX "
AB

2

Sì. Diversi produttori utilizzano un nome SDcard diverso come in Samsung Tab 3 il suo extsd, e altri dispositivi Samsung utilizzano sdcard come questo diverso produttore usano nomi diversi.

Avevo la tua stessa esigenza. quindi ho creato un esempio di esempio per te dal mio progetto vai a questo link Esempio di selezione della directory Android che utilizza la libreria androi-dirchooser. Questo esempio rileva la scheda SD ed elenca tutte le sottocartelle e rileva anche se il dispositivo ha più di una scheda SD.

Parte del codice è simile a questa Per un esempio completo vai al link Android Directory Chooser

/**
* Returns the path to internal storage ex:- /storage/emulated/0
 *
* @return
 */
private String getInternalDirectoryPath() {
return Environment.getExternalStorageDirectory().getAbsolutePath();
 }

/**
 * Returns the SDcard storage path for samsung ex:- /storage/extSdCard
 *
 * @return
 */
    private String getSDcardDirectoryPath() {
    return System.getenv("SECONDARY_STORAGE");
}


 mSdcardLayout.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        String sdCardPath;
        /***
         * Null check because user may click on already selected buton before selecting the folder
         * And mSelectedDir may contain some wrong path like when user confirm dialog and swith back again
         */

        if (mSelectedDir != null && !mSelectedDir.getAbsolutePath().contains(System.getenv("SECONDARY_STORAGE"))) {
            mCurrentInternalPath = mSelectedDir.getAbsolutePath();
        } else {
            mCurrentInternalPath = getInternalDirectoryPath();
        }
        if (mCurrentSDcardPath != null) {
            sdCardPath = mCurrentSDcardPath;
        } else {
            sdCardPath = getSDcardDirectoryPath();
        }
        //When there is only one SDcard
        if (sdCardPath != null) {
            if (!sdCardPath.contains(":")) {
                updateButtonColor(STORAGE_EXTERNAL);
                File dir = new File(sdCardPath);
                changeDirectory(dir);
            } else if (sdCardPath.contains(":")) {
                //Multiple Sdcards show root folder and remove the Internal storage from that.
                updateButtonColor(STORAGE_EXTERNAL);
                File dir = new File("/storage");
                changeDirectory(dir);
            }
        } else {
            //In some unknown scenario at least we can list the root folder
            updateButtonColor(STORAGE_EXTERNAL);
            File dir = new File("/storage");
            changeDirectory(dir);
        }


    }
});

2

Questa soluzione (assemblata da altre risposte a questa domanda) gestisce il fatto (come menzionato da @ono) che non System.getenv("SECONDARY_STORAGE")è di alcuna utilità con Marshmallow.

Testato e funzionante su:

  • Samsung Galaxy Tab 2 (Android 4.1.1 - Stock)
  • Samsung Galaxy Note 8.0 (Android 4.2.2 - Stock)
  • Samsung Galaxy S4 (Android 4.4 - Stock)
  • Samsung Galaxy S4 (Android 5.1.1 - Cyanogenmod)
  • Samsung Galaxy Tab A (Android 6.0.1 - Stock)

    /**
     * Returns all available external SD-Card roots in the system.
     *
     * @return paths to all available external SD-Card roots in the system.
     */
    public static String[] getStorageDirectories() {
        String [] storageDirectories;
        String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            List<String> results = new ArrayList<String>();
            File[] externalDirs = applicationContext.getExternalFilesDirs(null);
            for (File file : externalDirs) {
                String path = file.getPath().split("/Android")[0];
                if((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Environment.isExternalStorageRemovable(file))
                        || rawSecondaryStoragesStr != null && rawSecondaryStoragesStr.contains(path)){
                    results.add(path);
                }
            }
            storageDirectories = results.toArray(new String[0]);
        }else{
            final Set<String> rv = new HashSet<String>();
    
            if (!TextUtils.isEmpty(rawSecondaryStoragesStr)) {
                final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);
                Collections.addAll(rv, rawSecondaryStorages);
            }
            storageDirectories = rv.toArray(new String[rv.size()]);
        }
        return storageDirectories;
    }

La condizione rawSecondaryStoragesStr.contains(path)può consentire anche l'aggiunta della memoria interna; possiamo rimuovere meglio quella condizione .. Ho affrontato questo problema, poiché il mio dispositivo restituisce la directory di archiviazione interna con System.getenv("SECONDARY_STORAGE"), ma restituisce il percorso della scheda di memoria esterna con System.getenv(EXTERNAL_STORAGE)su KitKat; sembra che diversi fornitori lo abbiano implementato in modo diverso senza alcun dannato standard ..
Gokul NC

Ecco la mia soluzione che funziona fino a Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

1

Su alcuni dispositivi (ad esempio Samsung Galaxy SII) la scheda di memoria interna può essere in vfat. In questo caso si usa fare riferimento all'ultimo codice, si ottiene il percorso della scheda di memoria interna (/ mnt / sdcad) ma nessuna scheda esterna. Il codice riportato di seguito risolve questo problema.

static String getExternalStorage(){
         String exts =  Environment.getExternalStorageDirectory().getPath();
         try {
            FileReader fr = new FileReader(new File("/proc/mounts"));       
            BufferedReader br = new BufferedReader(fr);
            String sdCard=null;
            String line;
            while((line = br.readLine())!=null){
                if(line.contains("secure") || line.contains("asec")) continue;
            if(line.contains("fat")){
                String[] pars = line.split("\\s");
                if(pars.length<2) continue;
                if(pars[1].equals(exts)) continue;
                sdCard =pars[1]; 
                break;
            }
        }
        fr.close();
        br.close();
        return sdCard;  

     } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}

1
       File[] files = null;
    File file = new File("/storage");// /storage/emulated
if (file.exists()) {
        files = file.listFiles();
            }
            if (null != files)
                for (int j = 0; j < files.length; j++) {
                    Log.e(TAG, "" + files[j]);
                    Log.e(TAG, "//--//--// " +             files[j].exists());

                    if (files[j].toString().replaceAll("_", "")
                            .toLowerCase().contains("extsdcard")) {
                        external_path = files[j].toString();
                        break;
                    } else if (files[j].toString().replaceAll("_", "")
                            .toLowerCase()
                            .contains("sdcard".concat(Integer.toString(j)))) {
                        // external_path = files[j].toString();
                    }
                    Log.e(TAG, "--///--///--  " + external_path);
                }

0

Sono sicuro che questo codice risolverà sicuramente i tuoi problemi ... Funziona bene per me ... \

try {
            File mountFile = new File("/proc/mounts");
            usbFoundCount=0;
            sdcardFoundCount=0;
            if(mountFile.exists())
             {
                Scanner usbscanner = new Scanner(mountFile);
                while (usbscanner.hasNext()) {
                    String line = usbscanner.nextLine();
                    if (line.startsWith("/dev/fuse /storage/usbcard1")) {
                        usbFoundCount=1;
                        Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/usbcard1" );
                    }
            }
         }
            if(mountFile.exists()){
                Scanner sdcardscanner = new Scanner(mountFile);
                while (sdcardscanner.hasNext()) {
                    String line = sdcardscanner.nextLine();
                    if (line.startsWith("/dev/fuse /storage/sdcard1")) {
                        sdcardFoundCount=1;
                        Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/sdcard1" );
                    }
            }
         }
            if(usbFoundCount==1)
            {
                Toast.makeText(context,"USB Connected and properly mounted", 7000).show();
                Log.i("-----USB--------","USB Connected and properly mounted" );
            }
            else
            {
                Toast.makeText(context,"USB not found!!!!", 7000).show();
                Log.i("-----USB--------","USB not found!!!!" );

            }
            if(sdcardFoundCount==1)
            {
                Toast.makeText(context,"SDCard Connected and properly mounted", 7000).show();
                Log.i("-----SDCard--------","SDCard Connected and properly mounted" );
            }
            else
            {
                Toast.makeText(context,"SDCard not found!!!!", 7000).show();
                Log.i("-----SDCard--------","SDCard not found!!!!" );

            }
        }catch (Exception e) {
            e.printStackTrace();
        } 

Environment.getExternalStorageDirectory () non dovrebbe darti la posizione esatta della tua sdcard esterna o della posizione usb. Basta analizzare la posizione "/ proc / mounts" quindi / dev / fuse / storage / sdcard1 "ti darà la posizione se la tua sdcard è corretta montato o non uguale anche per usb.In questo modo puoi ottenerlo facilmente .. Saluti..Sam
Sam

0

non è vero. / mnt / sdcard / external_sd può esistere anche se la scheda SD non è montata. la tua applicazione andrà in crash quando provi a scrivere in / mnt / sdcard / external_sd quando non è montata.

è necessario verificare se la scheda SD è montata prima utilizzando:

boolean isSDPresent = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);

7
Questo non ha senso quando getExternalStorageState()restituisce la memoria interna piuttosto che la scheda SD esterna, penso.
Romulus Urakagi Ts'ai

Forniscono una funzione per ottenere una scheda SD esterna ora? Non riesco a trovare alcun indizio dopo aver cercato in giro per un'ora. Se questo è il caso, allora è così strano dopo così tante versioni aggiornate.
rml

Quando hai detto "non è vero", a cosa ti riferivi? Lo so, è stato 2,5 anni fa ...
LarsH

0
 String path = Environment.getExternalStorageDirectory()
                        + File.separator + Environment.DIRECTORY_PICTURES;
                File dir = new File(path);

4
Non funziona. Restituisce il percorso della memoria interna. ie / storage /

0

Puoi usare qualcosa come - Context.getExternalCacheDirs () o Context.getExternalFilesDirs () o Context.getObbDirs (). Forniscono directory specifiche dell'applicazione in tutti i dispositivi di archiviazione esterni in cui l'applicazione può memorizzare i propri file.

Quindi qualcosa di simile - Context.getExternalCacheDirs () [i] .getParentFile (). GetParentFile (). GetParentFile (). GetParent () può ottenere il percorso di root dei dispositivi di archiviazione esterni.

So che questi comandi hanno uno scopo diverso, ma altre risposte non hanno funzionato per me.

Questo collegamento mi ha dato buoni suggerimenti - https://possiblemobile.com/2014/03/android-external-storage/


0

System.getenv("SECONDARY_STORAGE")restituisce null per Marshmallow. Questo è un altro modo per trovare tutte le directory esterne. Puoi controllare se è rimovibile, il che determina se interno / esterno

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    File[] externalCacheDirs = context.getExternalCacheDirs();
    for (File file : externalCacheDirs) {
        if (Environment.isExternalStorageRemovable(file)) {
            // It's a removable storage
        }
    }
}

0

Ho provato le soluzioni fornite da Dmitriy Lozenko e Gnathonic sul mio Samsung Galaxy Tab S2 (Modello: T819Y) ma nessuna mi ha aiutato a recuperare il percorso di una directory della scheda SD esterna. mountl'esecuzione del comando conteneva il percorso richiesto alla directory della scheda SD esterna (cioè / Storage / A5F9-15F4) ma non corrispondeva all'espressione regolare, quindi non è stato restituito. Non ottengo il meccanismo di denominazione delle directory seguito da Samsung. Perché si discostano dagli standard (ad esempio extsdcard) e escogitano qualcosa di veramente strano come nel mio caso (ad esempio / Storage / A5F9-15F4), la . C'è qualcosa che mi manca? Comunque, a seguito dei cambiamenti nell'espressione regolare di Gnathonic la soluzione mi ha aiutato a ottenere una directory sdcard valida:

final HashSet<String> out = new HashSet<String>();
        String reg = "(?i).*(vold|media_rw).*(sdcard|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;

Non sono sicuro che questa sia una soluzione valida e se darà risultati per altri tablet Samsung, ma per ora ha risolto il mio problema. Di seguito è riportato un altro metodo per recuperare il percorso della scheda SD rimovibile in Android (v6.0). Ho testato il metodo con Android Marshmallow e funziona. L'approccio utilizzato in esso è molto semplice e funzionerà sicuramente anche per altre versioni, ma il test è obbligatorio. Alcune informazioni saranno utili:

public static String getSDCardDirPathForAndroidMarshmallow() {

    File rootDir = null;

    try {
        // Getting external storage directory file
        File innerDir = Environment.getExternalStorageDirectory();

        // Temporarily saving retrieved external storage directory as root
        // directory
        rootDir = innerDir;

        // Splitting path for external storage directory to get its root
        // directory

        String externalStorageDirPath = innerDir.getAbsolutePath();

        if (externalStorageDirPath != null
                && externalStorageDirPath.length() > 1
                && externalStorageDirPath.startsWith("/")) {

            externalStorageDirPath = externalStorageDirPath.substring(1,
                    externalStorageDirPath.length());
        }

        if (externalStorageDirPath != null
                && externalStorageDirPath.endsWith("/")) {

            externalStorageDirPath = externalStorageDirPath.substring(0,
                    externalStorageDirPath.length() - 1);
        }

        String[] pathElements = externalStorageDirPath.split("/");

        for (int i = 0; i < pathElements.length - 1; i++) {

            rootDir = rootDir.getParentFile();
        }

        File[] files = rootDir.listFiles();

        for (File file : files) {
            if (file.exists() && file.compareTo(innerDir) != 0) {

                // Try-catch is implemented to prevent from any IO exception
                try {

                    if (Environment.isExternalStorageRemovable(file)) {
                        return file.getAbsolutePath();

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

Condividi gentilmente se hai un altro approccio per gestire questo problema. Grazie


Ecco la mia soluzione che funziona fino a Nougat: stackoverflow.com/a/40205116/5002496
Gokul NC

Io in realtà ho lo stesso problema con voi su Asus Zenfone 2, ma io modificare il codice da Dmitriy Lozenko invece di risolvere il problema stackoverflow.com/a/40582634/3940133
HendraWD

@HendraWD la soluzione che stai suggerendo potrebbe non funzionare con Android Marshmallow (6.0) poiché il supporto per le variabili di ambiente è stato rimosso. Non riesco a ricordare esattamente, ma penso di averci provato.
Abdul Rehman

@ GokulNC Proverò. sembra legittimo :)
Abdul Rehman

@GokulNC sì, ecco perché uso context.getExternalFilesDirs (null); invece di utilizzare direttamente percorsi fisici quando la versione è> Marshmallow
HendraWD

0
String secStore = System.getenv("SECONDARY_STORAGE");

File externalsdpath = new File(secStore);

Questo otterrà il percorso della memoria secondaria sd esterna.


0
//manifest file outside the application tag
//please give permission write this 
//<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        File file = new File("/mnt");
        String[] fileNameList = file.list(); //file names list inside the mnr folder
        String all_names = ""; //for the log information
        String foundedFullNameOfExtCard = ""; // full name of ext card will come here
        boolean isExtCardFounded = false;
        for (String name : fileNameList) {
            if (!isExtCardFounded) {
                isExtCardFounded = name.contains("ext");
                foundedFullNameOfExtCard = name;
            }
            all_names += name + "\n"; // for log
        }
        Log.d("dialog", all_names + foundedFullNameOfExtCard);

Questo è in alternativa per i principianti che almeno ottengono stringList di tutti i driver montati nel dispositivo.
Emre Kilinc Arslan

0

Per accedere ai file nella mia scheda SD , sul mio HTC One X (Android), utilizzo questo percorso:

file:///storage/sdcard0/folder/filename.jpg

Nota il triplo "/"!


-1

Su Galaxy S3 Android 4.3 il percorso che uso è ./storage/extSdCard/Card/ e fa il lavoro. Spero che sia d'aiuto,


-1

I seguenti passaggi hanno funzionato per me. Hai solo bisogno di scrivere queste righe:

String sdf = new String(Environment.getExternalStorageDirectory().getName());
String sddir = new String(Environment.getExternalStorageDirectory().getPath().replace(sdf,""));

La prima riga darà il nome della directory sd, e devi solo usarlo nel metodo di sostituzione per la seconda stringa. La seconda stringa conterrà il percorso per l' SD interno e rimovibile (/ storage / nel mio caso) . Avevo solo bisogno di questo percorso per la mia app ma puoi andare oltre se ne hai bisogno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.