2012-04-23 22 views
5

Estoy buscando una manera de detectar y acceder a tarjetas sd extraíbles en una variedad de dispositivos Android (Samsung, Motorola, LG, Sony, HTC).¿Cómo acceder al almacenamiento extraíble en dispositivos Android?

También necesito ser compatible con 2.2 entonces Environment.isExternalStorageRemovable() no está disponible para mí.

Motorola tiene su propia biblioteca, y por Samsung que puede detectar la existencia de /external_sd/

no tengo ninguna pista para el resto de ellos. Por ejemplo, he visto un /_ExternalSD/ en algunos LG pero el directorio permanece incluso cuando se elimina el SD.

Una pregunta extra: será la intención ACTION_MEDIA_MOUNTED será transmitida por ninguno de ellos

Cualquier pista sobre esto sería muy útil.

+0

Todo lo que vaya más allá de los métodos de 'Environment' está fuera de los límites del SDK y no será confiable. – CommonsWare

Respuesta

0

Estas capacidades están disponibles en todas las versiones de Android:

  • Para obtener la carpeta de la aplicación en el almacenamiento externo, llame Context.getExternalFilesDir.

  • Tenga en cuenta que su aplicación necesita permiso explícito para acceder al almacenamiento externo, y que usted debe comprobar si está disponible a través de Environment.getExternalStorageState

  • Y sí, ACTION_MEDIA_MOUNTED se transmitirá cada vez que los medios extraíbles se hace accesible (debe también escuche ACTION_MEDIA_EJECT y ACTION_MEDIA_REMOVED)

+0

Gracias Tony, pero esto solo devolverá/mnt/sdcard que no es el dispositivo de almacenamiento extraíble. He editado mi pregunta para que esté formulada con precisión. – znat

+0

Sí, el almacenamiento externo es * generalmente *, pero no * siempre * extraíble. ¿Cuál es tu caso de uso exacto? –

+0

La aplicación debe proporcionar una selección de dispositivos de almacenamiento para descargas. Por lo general, dispositivo de almacenamiento extraíble interno vs externo. Por lo que veo, la separación no es tan clara. P.ej. Samsung monta el SD extraíble en/mnt/sdcard/external_sd. LG en/mnt/sdcard/_ExternalSD/pero el directorio y algunos archivos permanecen incluso si el extraíble está desconectado. Lo que sugiere que no existe una separación lógica – znat

3

Aquí es una clase que utilizo para encontrar todos sdcards en un dispositivo; incorporado y extraíble. Lo he estado usando en Ice Cream Sandwich, pero debería funcionar en niveles 2x.

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

}

El MyLog.d es una clase de seguimiento que se expande Log.d - que se puede quitar.

La clase lee/proc/mounts/e:

  1. comprueba si el nombre de ruta es el directorio sdcard interna
  2. comprobaciones para ver si es un dispositivo de bloque
  3. saltos mtdblock dispositivos
  4. se salta nada que no esté montado
  5. saltos directorios seguros y ASEC
  6. se asegura de que exista, es un directorio, y leer/escritura accesible

Si todo esto coincide, se supone que usted tiene una tarjeta sd y agrega la ruta a la lista de la matriz. Devuelve una matriz de cadenas de nombres de ruta.

llamar a la función GetDirectories, código de algo similar a:

String[] sdcardDirectories = GetRemoveableDevice.getDirectories(); 

Los caminos devueltos se pueden utilizar para crear una lista de selección de usuario, explorar en busca de un archivo, o lo que sea.

Finalmente, aquí está dos líneas de MyLog.d procedentes de un ensayo emulador (segunda línea es el sdcard emulador):

09-19 15: 57: 12.511: D/GetRemoveableDevice (651): lineRead:/dev/block/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, página de códigos = cp437, iocharset = iso8859-1, shortname = mixed, utf8, errors = remontar -ro 0 0

+0

Ooops. Olvidé mencionar que al verificar el estado de lectura/escritura, se eliminan las tarjetas SD que aún tienen una entrada en el directorio/mnt /. –

+0

Sé que este hilo es antiguo, pero estoy convirtiendo algún código de detección de almacenamiento en una biblioteca de propósito general y quiero distinguir entre el almacenamiento externo que es permanente y el que es realmente extraíble. No sé si su solución cumple con ese requisito?Parece que la primera instrucción "si" en su ciclo almacenará cualquier ocurrencia de la ruta devuelta por "getExternalStorageDirectory()", que en la mayoría de los casos NO es físicamente eliminable, ¿verdad? –

+0

Perdón por tomar tanto tiempo. Se dirige al teclado trabajando en el proyecto. Para responder, sí, la ruta de getExtenalStorageDirectory es normalmente la tarjeta SD que no se puede montar. La primera entrada en la lista devuelta es la tarjeta SD getExternal. Si la lista tiene entradas múltiples, use la segunda entrada o una posterior. También puede verificar si puede desmontarse. Además, puede hacer un proyecto simple para mostrar la lista (y cualquier otra cosa que quiera) y luego verificar qué ocurre cuando elimina y reemplaza la (s) tarjeta (s) sd extraíble (s). –

1

Basado en la clase de Howards hice algunas modificaciones ons para que funcione en el Galaxy S3.

  1. Environment.getExternalStorageDirectory() devuelve almacenamiento interno en el S3.
  2. de almacenamiento extraíble no está montado necesariamente bajo/mnt
  3. Los medios extraíbles deben tener sistema de archivos 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

creo que este tampoco es el camino recomendado por google. – Raghunandan

+2

Acepto que es un truco. Pero este es el truco más limpio que he visto. Si encuentra una forma adecuada, por favor háganos saber. – tmanthey

+0

cómo es diferente de la que publiqué – Raghunandan

1

Basado en las 2 clases presentados anteriormente he modificado la clase adicional en darse cuenta de que todo el almacenamiento extraíble externo en varios teléfonos y tabletas que pude encontrar se montó utilizando vold, el daemon de montaje de volumen.

  // 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

Gracias por compartir lo que has aprendido. +1. Recuerde que "arriba" no es una propiedad estable de respuestas ... actualmente hay 3 otras clases en esta página, y las 2 clases a las que se refiere pueden aparecer debajo de la suya cuando alguien ve esta página. – LarsH

0

Este es el método que he creado y estoy usando. Esto ha funcionado en Samsung Galaxy S4, Samsung Galaxy Note 3 y 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; 
} 
Cuestiones relacionadas