2012-04-23 13 views
5

Sto cercando un modo per rilevare e accedere a schede SD rimovibili su vari dispositivi Android (Samsung, Motorola, LG, Sony, HTC).Come accedere alla memoria rimovibile sui dispositivi Android?

Devo anche essere compatibile con 2.2 quindi Environment.isExternalStorageRemovable() non è disponibile per me.

Motorola ha la sua biblioteca e per Samsung io in grado di rilevare l'esistenza di /external_sd/

non ho alcun indizio per il resto di loro. Ad esempio, ho visto uno /_ExternalSD/ su alcuni LG, ma la directory rimane anche quando la SD viene rimossa.

Una domanda bonus: sarà l'intento ACTION_MEDIA_MOUNTED in onda per nessuno di loro

Qualsiasi suggerimento su questo sarebbe molto utile.

+0

Qualsiasi cosa oltre i metodi di 'Ambiente' è oltre i limiti dell'SDK e sarà inaffidabile. – CommonsWare

risposta

0

Queste funzionalità sono disponibili in tutte le versioni di Android:

  • Per ottenere cartella dell'applicazione sulla memoria esterna, chiamata Context.getExternalFilesDir.

  • Tenete a mente che la vostra applicazione ha bisogno esplicita autorizzazione per accedere storage esterno, e che si dovrebbe verificare se è disponibile tramite Environment.getExternalStorageState

  • E sì, sarà trasmessa in ACTION_MEDIA_MOUNTED ogni volta che un supporto rimovibile diventa accessibile (si dovrebbe anche ascoltare per ACTION_MEDIA_EJECT e ACTION_MEDIA_REMOVED)

+0

Grazie Tony, ma questo restituirà/mnt/sdcard che non è il dispositivo di archiviazione rimovibile. Ho modificato la mia domanda in modo che sia formulata con precisione. – znat

+0

Sì, la memoria esterna è * solitamente *, ma non * sempre * rimovibile. Qual è il tuo caso d'uso esatto? –

+0

L'app deve fornire una scelta di dispositivi di archiviazione per i download. Dispositivo di archiviazione rimovibile in genere interno o esterno. Da quello che vedo, la separazione non è così chiara. Per esempio. Samsung monta il sd su/mnt/sdcard/external_sd rimovibile. LG su/mnt/sdcard/_ExternalSD/ma la directory e alcuni file rimangono anche se l'unità rimovibile è scollegata. Che suggeriscono che non vi è alcuna separazione logica – znat

3

Ecco una classe che uso per trovare tutte le SDcards su un dispositivo; integrato e rimovibile. L'ho usato su Ice Cream Sandwich, ma dovrebbe funzionare a 2 livelli.

public class GetRemovableDevice { 

private final static String TAG = "GetRemoveableDevice"; 

public GetRemovableDevice() { 
} 

public static String[] getDirectories() { 
    MyLog.d(TAG, "getStorageDirectories"); 
    File tempFile; 
    String[] directories = null; 
    String[] splits; 
    ArrayList<String> arrayList = new ArrayList<String>(); 
    BufferedReader bufferedReader = null; 
    String lineRead; 

    try { 
     arrayList.clear(); // redundant, but what the hey 
     bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

     while ((lineRead = bufferedReader.readLine()) != null) { 
      MyLog.d(TAG, "lineRead: " + lineRead); 
      splits = lineRead.split(" "); 

      // System external storage 
      if (splits[1].equals(Environment.getExternalStorageDirectory() 
        .getPath())) { 
       arrayList.add(splits[1]); 
       MyLog.d(TAG, "gesd split 1: " + splits[1]); 
       continue; 
      } 

      // skip if not external storage device 
      if (!splits[0].contains("/dev/block/")) { 
       continue; 
      } 

      // skip if mtdblock device 

      if (splits[0].contains("/dev/block/mtdblock")) { 
       continue; 
      } 

      // skip if not in /mnt node 

      if (!splits[1].contains("/mnt")) { 
       continue; 
      } 

      // skip these names 

      if (splits[1].contains("/secure")) { 
       continue; 
      } 

      if (splits[1].contains("/mnt/asec")) { 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      tempFile = new File(splits[1]); 
      if (!tempFile.exists()) { 
       continue; 
      } 
      if (!tempFile.isDirectory()) { 
       continue; 
      } 
      if (!tempFile.canRead()) { 
       continue; 
      } 
      if (!tempFile.canWrite()) { 
       continue; 
      } 

      // Met all the criteria, assume sdcard 
      arrayList.add(splits[1]); 
     } 

    } catch (FileNotFoundException e) { 
    } catch (IOException e) { 
    } finally { 
     if (bufferedReader != null) { 
      try { 
       bufferedReader.close(); 
      } catch (IOException e) { 
      } 
     } 
    } 

    // Send list back to caller 

    if (arrayList.size() == 0) { 
     arrayList.add("sdcard not found"); 
    } 
    directories = new String[arrayList.size()]; 
    for (int i = 0; i < arrayList.size(); i++) { 
     directories[i] = arrayList.get(i); 
    } 
    return directories; 
} 

}

Il MyLog.d è una classe di traccia che si espande Log.d - può essere eliminato.

La classe si legge/proc/mounts/e:

  1. controlla se il nome del percorso è la directory sdcard interna
  2. controlli per vedere se un dispositivo a blocchi
  3. cassonetti mtdblock dispositivi
  4. salta tutto ciò che non è montata
  5. cassonetti directory sicuri e ASEC
  6. si assicura che esiste, è una directory, e leggere/write accessibile

Se tutto questo corrisponde, si presuppone che si disponga di una sdcard e si aggiunga il percorso all'elenco di array. Restituisce una serie di stringhe di nomi di percorsi.

per chiamare la funzione GetDirectories, codice di qualcosa di simile a:

String[] sdcardDirectories = GetRemoveableDevice.getDirectories(); 

I percorsi restituiti può essere utilizzato per creare una lista di selezione utente, eseguire la scansione di un file, o qualsiasi altra cosa.

Infine, ecco due linee di MyLog.d da un test emulatore (seconda riga è l'emulatore sdcard):

09-19 15: 57: 12,511: D/GetRemoveableDevice (651): lineRead:/dev/blocco/mtdblock2/cache YAFFS2 RW, nosuid, nodev 0 0

09-19 15: 57: 12,511: D/GetRemoveableDevice (651): lineRead:/dev/block/vold/179: 0/mnt/sdcard vfat rw, dirsync, nosuid, nodev, noexec, uid = 1000, gid = 1015, fmask = 0702, dmask = 0702, allow_utime = 0020, codepage = cp437, iocharset = iso8859-1, shortname = mixed, utf8, errors = remount -ro 0 0

+0

Ooops. Ho dimenticato di dire che il controllo dello stato di lettura/scrittura elimina le sdcard non montate che hanno ancora una voce nella directory/mnt /. –

+0

So che questo thread è obsoleto, ma sto convertendo un codice di rilevamento dell'archiviazione in una libreria generica e voglio distinguere tra lo storage esterno permanente e quello rimovibile. Non so se la tua soluzione soddisfa questo requisito?Sembra che la prima istruzione "if" nel tuo ciclo memorizzerà qualsiasi occorrenza del percorso restituito da "getExternalStorageDirectory()", che molto spesso NON è fisicamente rimovibile, giusto? –

+0

Ci scusiamo per prendere così tanto tempo. Testa alla tastiera lavorando al progetto. Per rispondere, sì, il percorso da getExtenalStorageDirectory è normalmente la sdcard smontabile. La prima voce nella lista restituita è la sdcard getExternal. Se l'elenco ha più voci, utilizzare la seconda o successiva voce. Puoi anche controllare se può essere smontato. Inoltre, è possibile creare un progetto semplice per visualizzare l'elenco (e qualsiasi altra cosa si desideri) e quindi controllare cosa succede quando si rimuovono e si sostituiscono le sdcard rimovibili. –

1

Sulla base della classe Howards ho apportato alcune modifiche per farlo funzionare sul Galaxy S3.

  1. Environment.getExternalStorageDirectory() restituisce memoria interna su S3.
  2. memorizzazione rimovibile non è necessariamente montato sotto/mnt
  3. supporti rimovibili devono avere vfat

_

public static String getDirectory() { 
     Log.d(TAG, "getStorageDirectories"); 
     File tempFile; 
     String[] splits; 
     ArrayList<String> arrayList = new ArrayList<String>(); 
     BufferedReader bufferedReader = null; 
     String lineRead; 

     try { 
      arrayList.clear(); // redundant, but what the hey 
      bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

      while ((lineRead = bufferedReader.readLine()) != null) { 
       Log.d(TAG, "lineRead: " + lineRead); 
       splits = lineRead.split(" "); 

       // skip if not external storage device 
       if (!splits[0].contains("/dev/block/")) { 
        continue; 
       } 

       // skip if mtdblock device 
       if (splits[0].contains("/dev/block/mtdblock")) { 
        continue; 
       } 

       // skip if not in vfat node 
       if (!splits[2].contains("vfat")) { 
        continue; 
       } 

       // skip these names 
       if (splits[1].contains("/secure")) { 
        continue; 
       } 

       if (splits[1].contains("/mnt/asec")) { 
        continue; 
       } 

       // Eliminate if not a directory or fully accessible 
       tempFile = new File(splits[1]); 
       if (!tempFile.exists()) { 
        continue; 
       } 
       if (!tempFile.isDirectory()) { 
        continue; 
       } 
       if (!tempFile.canRead()) { 
        continue; 
       } 
       if (!tempFile.canWrite()) { 
        continue; 
       } 

       // Met all the criteria, assume sdcard 
       return splits[1]; 
      } 

     } catch (FileNotFoundException e) { 
     } catch (IOException e) { 
     } finally { 
      if (bufferedReader != null) { 
       try { 
        bufferedReader.close(); 
       } catch (IOException e) { 
       } 
      } 
     } 

     return null; 
    } 
+0

credo che anche questo non sia raccomandato da google. – Raghunandan

+2

Sono d'accordo è un trucco. Ma questo è il trucco più pulito che ho visto. Se trovi un modo corretto, faccelo sapere. – tmanthey

+0

come è diverso da quello che ho postato – Raghunandan

1

Sulla base delle 2 classi presentate in precedenza ho modificato la classe più avanti notando che tutto lo spazio di archiviazione rimovibile esterno su diversi telefoni e tablet che sono riuscito a trovare sono stati montati usando vold, il demone di montaggio del volume.

  // skip if not external storage device 
      if (!splits[0].contains("vold")) { 
       continue; 
      } 

      if (splits[1].contains("/mnt/asec")) { 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      tempFile = new File(splits[1]); 
      if (!tempFile.exists()) { 
       continue; 
      } 
      if (!tempFile.isDirectory()) { 
       continue; 
      } 
      if (!tempFile.canRead()) { 
       continue; 
      } 
      if (!tempFile.canWrite()) { 
       continue; 
      } 

      // Met all the criteria, assume sdcard 
      arrayList.add(splits[1]); 
+0

Grazie per aver condiviso ciò che hai imparato. +1. Per favore ricorda che "sopra" non è una proprietà stabile di risposte ... ci sono attualmente 3 altre classi su questa pagina, e le 2 classi a cui ti riferisci possono apparire sotto le tue quando qualcuno visualizza questa pagina. – LarsH

0

Questo è il metodo che ho creato e sto usando. Questo ha funzionato su Samsung Galaxy S4, Samsung Galaxy Note 3 e Sony Xperia Z2.

private static String[] getRemovableStoragePaths() { 
    String[] directories; 
    String[] splits; 
    ArrayList<String> pathList = new ArrayList<String>(); 
    BufferedReader bufferedReader = null; 
    String lineRead; 

    try { 
     bufferedReader = new BufferedReader(new FileReader("/proc/mounts")); 

     while ((lineRead = bufferedReader.readLine()) != null) { 
      Log.d(TAG, "lineRead: " + lineRead); 
      splits = lineRead.split(" "); 
      Log.d(TAG, "Testing path: " + splits[1]); 

      if (!splits[1].contains("/storage")) { 
       continue; 
      } 

      if (splits[1].contains("/emulated")) { 
       // emulated indicates an internal storage location, so skip it. 
       continue; 
      } 

      // Eliminate if not a directory or fully accessible 
      Log.d(TAG, "Path found: " + splits[1]); 

      // Met all the criteria, assume sdcard 
      pathList.add(splits[1]); 
     } 

    } catch (FileNotFoundException e) { 
    } catch (IOException e) { 
    } finally { 
     if (bufferedReader != null) { 
      try { 
       bufferedReader.close(); 
      } catch (IOException e) { 
      } 
     } 
    } 

    // Send list back to caller 

    if (pathList.size() == 0) { 
     pathList.add("sdcard not found"); 
    } else { 
     Log.d(TAG, "Found potential removable storage locations: " + pathList); 
    } 
    directories = new String[pathList.size()]; 
    for (int i = 0; i < pathList.size(); i++) { 
     directories[i] = pathList.get(i); 
    } 
    return directories; 
} 
Problemi correlati