domingo, 14 de diciembre de 2014

Ficheros en Memoria Externa (Tarjeta SD) - Android



En el apartado anterior del curso hemos visto cómo manipular ficheros localizados en la memoria interna de un dispositivo Android. Sin embargo, como ya indicamos, esta memoria suele ser relativamente limitada y no es aconsejable almacenar en ella ficheros de gran tamaño. La alternativa natural es utilizar para ello la memoria externa del dispositivo, constituida normalmente por una tarjeta de memoria SD, aunque en dispositivos recientes también está presente en forma de almacenamiento no extraíble del dispositivo, aunque no por ello debe confundirse con la memoria interna. A diferencia de la memoria interna, el almacenamiento externo es público, es decir, todo lo que escribamos en él podrá ser leído por otras aplicaciones y por el usuario, por tanto hay que tener cierto cuidado a la hora de dicidir lo que escribimos en memoria interna y externa.

Una nota rápida antes de empezar con este tema. Para poder probar aplicaciones que hagan uso de la memoria externa en el emulador de Android necesitamos tener configurado en Eclipse un AVD que tenga establecido correctamente el tamaño de la tarjeta SD. En mi caso, he definido por ejemplo un tamaño de tarjeta de 50 Mb:


Seguimos. A diferencia de la memoria interna, la tarjeta de memoria no tiene por qué estar presente en el dispositivo, e incluso estándolo puede no estar reconocida por el sistema. Por tanto, el primer paso recomendado a la hora de trabajar con ficheros en memoria externa es asegurarnos de que dicha memoria está presente y disponible para leer y/o escribir en ella.

Para esto la API de Android proporciona (como método estático dela clase Environment) el método getExternalStorageStatus(), que no dice si la memoria externa está disponible y si se puede leer y escribir en ella. Este método devuelve una serie de valores que nos indicarán el estado de la memoria externa, siendo los más importantes los siguientes:

> MEDIA_MOUNTED, que indica que la memoria externa está disponible y podemos tanto leer como escribir en ella.
> MEDIA_MOUNTED_READ_ONLY, que indica que la memoria externa está disponible pero sólo podemos leer de ella.

> Otra serie de valores que indicarán que existe algún problema y que por tanto no podemos ni leer ni escribir en la memoria externa (MEDIA_UNMOUNTED, MEDIA_REMOVED, …). Podéis consultar todos estos estados en la documentación oficial de la clase Environment.

Con todo esto en cuenta, podríamos realizar un chequeo previo del estado de la memoria externa del dispositivo de la siguiente forma:


Una vez chequeado el estado de la memoria externa, y dependiendo del resultado obtenido, ya podremos leer o escribir en ella cualquier tipo de fichero.

Empecemos por la escritura. Para escribir un fichero a la memoria externa tenemos que obtener en primer lugar la ruta al directorio raíz de esta memoria. Para ello podemos utilizar el método getExternalStorageDirectory() de la clase Environment, que nos devolverá un objeto File con la ruta de dicho directorio. A partir de este objeto, podremos construir otro con el nombre elegido para nuestro fichero (como ejemplo "prueba_sd.txt"), creando un nuevo objeto File que combine ambos elementos. Tras esto, ya sólo queda encapsularlo en algún objeto de escritura de ficheros de la API de java y escribir algún dato de prueba. En nuestro caso de ejemplo lo convertiremos una vez más a un objeto OutputStreamWriter para escribir al fichero un mensaje de texto. Veamos cómo quedaría el código:


El código anterior funcioa sin problemas pero escribirá el fichero directamente en la carpeta raíz de la memoria externa. Esto, aunque en ocasiones puede resultar necesario, no es una buena práctica. Lo correcto sería disponer de una carpeta propia para nuestra aplicación, lo que además tendrá la ventaja de que al desinstalar la aplicación también se liberará este espacio. Esto lo conseguimos utilizando el método getExternalFilesDir(null) en vez de getExternalStorageDirectory(). El método getExternalFilesDir() nos devuelve directamente la ruta de una carpeta específica para nuestra aplicación dentro de la memoria externa siguiendo el siguiente patrón:

<raíz_mem_ext>/Android/data/nuestro.paquete.java/files

Si en vez de null le indicamos como parámetro un tipo de datos determinado (DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_MOVIES, DIRECTORY_RINGTONES, DIRECTORY_ALARMS, DIRECTORY_NOTIFICATIONS, DIRECTORY_PODCASTS) nos devolverá una subcarpeta dentro de la anterior con su nombre correspondiente. Así, por ejemplo, una llamada al método getExternalFilesDir(Environment.DIRECTORY_MUSIC) nos devolvería la siguiente carpeta:

<raíz_mem_ext>/Android/data/nuestro.paquete.java/files/Music

Esto último, además, ayuda a Android a saber qué tipo de contenidos hay en cada carpeta, de forma que puedan clasificarse correctamente por ejemplo en la galería multimedia.

Sea como sea, para tener acceso a la memoria externa tendremos que especificar en el fichero AndroidManifest.xml que nuestra aplicación necesita permiso de escritura en dicha memoria. Para añadir un nuevo permiso usaremos como siempre la cláusula <uses-permission> utilizando el valor concreto "android.permission.WRITE_EXTERNAL_STORAGE". Con esto, nuestro AndroidManifest.xml quedaría de forma similar a éste:


Si ejecutamos ahora el código y nos vamos al explorador de archivos del DDMS podremos comprobar cómo se ha creado correctamente el fichero en el directorio raíz de nuestra SD. Esta ruta puede variar entre dispositivos, pero para Android 2.x suele localizarse en la carpeta /sdcard/, mientras que para Android 4 suele estar en /mnt/sdcard/.


Por su parte, leer un fichero desde la memoria externa es igual de sencillo. Obtenemos el directorio raíz de la memoria externa con getExternalStorageDirectory() o la carpeta específica de nuestra aplicación con getExternalFilesDir() como ya hemos visto, creamos un objeto File que combine esa ruta con el nombre del fichero a leer y lo encapsulamos dentro de algún objeto que facilite la lectura, nosotros para leer texto utilizaremos como siempre un BufferedReader.


Como vemos, el código es análogo al que hemos visto para la escritura de ficheros.

Como aplicación de ejemplo de este apartado he partido de la desarrollada en el anterior dedicado a la memoria interna y he añadido dos nuevos botones para leer y escribir a memoria externa tal como hemos descrito. Los resultados se muestran en el log de la aplicación.


Saludos compañeros, aprovechen la información.









No hay comentarios:

Publicar un comentario en la entrada