Inicio Android Ficheros en Android (II): Memoria Externa (Tarjeta SD)

Ficheros en Android (II): Memoria Externa (Tarjeta SD)

por sgoliver

En el artículo 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:

avd_sd_card_size

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:

boolean sdDisponible = false;
boolean sdAccesoEscritura = false;

//Comprobamos el estado de la memoria externa (tarjeta SD)
String estado = Environment.getExternalStorageState();

if (estado.equals(Environment.MEDIA_MOUNTED))
{
	sdDisponible = true;
	sdAccesoEscritura = true;
}
else if (estado.equals(Environment.MEDIA_MOUNTED_READ_ONLY))
{
	sdDisponible = true;
	sdAccesoEscritura = false;
}
else
{
	sdDisponible = false;
	sdAccesoEscritura = false;
}

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:

try
{
	File ruta_sd = Environment.getExternalStorageDirectory();

	File f = new File(ruta_sd.getAbsolutePath(), "prueba_sd.txt");

	OutputStreamWriter fout =
		new OutputStreamWriter(
			new FileOutputStream(f));

	fout.write("Texto de prueba.");
	fout.close();
}
catch (Exception ex)
{
	Log.e("Ficheros", "Error al escribir fichero a tarjeta SD");
}

El código anterior funciona 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:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.sgoliver.android.ficheros"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="net.sgoliver.android.ficheros.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

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

ddms_fileexplorer_sdcard

Por su parte, leer un fichero desde la memoria externa es igual de sencillo. Obtenemos el directorio raiz 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 lectura, nosotros para leer texto utilizaremos como siempre un BufferedReader.

try
{
	File ruta_sd = Environment.getExternalStorageDirectory();

	File f = new File(ruta_sd.getAbsolutePath(), "prueba_sd.txt");

	BufferedReader fin =
		new BufferedReader(
			new InputStreamReader(
				new FileInputStream(f)));

	String texto = fin.readLine();
	fin.close();
}
catch (Exception ex)
{
	Log.e("Ficheros", "Error al leer fichero desde tarjeta SD");
}

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

Como aplicación de ejemplo de este artículo he partido de la desarrollada en el artículo 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.

captura-android-ficheros

Puedes consultar y/o descargar el código completo de los ejemplos desarrollados en este artículo accediendo a la página del curso en GitHub.

Curso de Programación Android en PDF

Este curso también está disponible en PDF. Descubre cómo conseguirlo…

¿Te ha sido de utilidad el Curso de Programación Android? ¿Quieres colaborar de forma económica con el proyecto? Puedes contribuir con cualquier cantidad, unos céntimos, unos euros, cualquier aportación será bienvenida. Además, si tu aportación es superior a una pequeña cantidad simbólica recibirás como agradecimiento un documento con la última versión del curso disponible en formato PDF. Sea como sea, muchas gracias por colaborar!

Más información:

También te puede interesar

29 comentarios

Desarrollo en Android | sgoliver.net blog 06/07/2011 - 11:22

[…] Ficheros en Android (II): Memoria Externa (Tarjeta SD) [Nuevo!] […]

Responder
Juan 11/07/2011 - 16:38

Hola, muchísimas gracias por los tutoriales de Android.

Tengo una pregunta, deseo descargar un fichero desde el un servidor local para después leerlo desde android. ¿Como lo podría hacer?

En cuánto pueda hago una donación (aún no tengo paypal), ya que me parece una buena iniciativa y el dinero es por una buena causa.

Un saludo y enhorabuena por este magnífico blog.

Responder
Totttovsky 10/08/2011 - 2:56

Amigo, tienes una web con excelente información. Con gusto te hare un donativo para disponer de tu PDF que ahora que comienzo con Androir se que me sera de mucha ayuda. Solo esperare algunas cosas por aca y te hare el donativo con su respectivo aviso. Se agradece mucho la info que has publicado. Saludos y estamos leyendonos por aqui.

Responder
Trotosvky 27/08/2011 - 12:08

No se deberian escribir archivos en la raiz de la tarjeta SD y es una de las cosas que mas odio de las aplicaciones mal hechas porque, 1) no hay una organizacion y 2) si se desinstala la aplicacion los archivos no se borran.

Por favor, en android existe un metodo que es:
getExternalFilesDir (null).getAbsolutePath ()
y que devuelve la ruta donde tu aplicacion puede crear y borrar ficheros libremente porque una vez desinstalas se borran automaticamente.

Asi que por el momento este tutorial enseña a hacer un mal uso de la tarjeta SD. Que nadie lo siga y espero que todos los que leais este mensaje de ahora en adelante useis el metodo que he descrito.

Responder
sgoliver 27/08/2011 - 19:08

Hola Trotosvky, efectivamente existe el método que mencionas en tu comentario, y explicas bien su función y los buenos motivos para utilizarlo, pero sólo funciona a partir de la versión 2.2 de Android en adelante. Sin embargo, el método getExternalStorageDirectory() para un acceso genérico a la SD funciona desde la primera versión del SDK y de ahí que lo eligiera para este tutorial.

Estoy de acuerdo contigo en que hay que «aprender a utilizar bien» las cosas, pero antes que eso hay que «aprender a utilizarlas» (a secas). Y para eso escribí este tutorial.

De cualquier forma, ya que lo has mencionado, intentaré añadir una nota al artículo para indicar el lugar idóneo de la tarjeta SD donde deberíamos guardar nuestros ficheros.

Responder
Víctor 28/10/2011 - 20:20

Hola, estás haciendo una labor excelente amigo, he aprendido muchísimo con tus explicaciones.

Tengo una duda… Si quiero abrir un fichero de la SD para AÑADIR más texto (sin machacar lo que ya contiene, al estilo del parámetro «a» en C)… ¿cómo se hace?

Un saludo.

Responder
Rodney 11/11/2011 - 22:43

Hola muchas gracias por el post esta muy bueno, me ha ayudado mucho estoy haciendo un proyecto en el cual debo imprimir una factura o por lo menos mandar un archivo txt asi como lo mandas en el post pero no solo de una linea sino de varias y ademas aignandole o mandando en ese archivo txt la imformacion que tengan unos editext si pudieras ayudarme con estas dos inquietudes te agradeceria de verdad es solo como puedo meter lo que tenga en unos edittext en el archivo a imprimir y hacer por decirlo asi un salto de linea

Responder
WILLIAM GARCIA 23/11/2011 - 18:54

Hola saludos!! quiero leer unos imagenes pero quiero colocar las imagenes en la sdcard desde mi pc, donde queda dentro del emulador la SDCARD?

Saludos!

Responder
johnny 10/04/2012 - 0:19

hola, tengo una duda, hay forma de realizar algo parecido a esto pero con una base de datos?? se puede gestionar una base de datos desde la sd card???

Responder
tecop 29/04/2012 - 16:40

Hola, ¿podrías hacer un ejemplo sobre una lista de los diferentes directorios y diferentes archivos pudiendo recorrerlos e interactuar? Se me pide utilizar una clase «ArrayAdapter», pero esta va asociada a la típica clase Artículo o Model, y no se como combinarlo con todo esto de los archivos. Vengo de construir listas y menús y ahora empecé con archivos y demás, pero unirlo todo me desborda. Además se me pide diferenciar diferentes tipos de archivos con colores o iconos y dar el tamaño de los ficheros, y si se clicka en alguno sale un mensaje, hay un botón para volver al directorio anterior y el principal.
Se que es mucho pedir, pero si estás interesado en añadir este ejemplo a tu blog, me ayudarías mucho. Si quieres te puedo pasar el .apk del ejemplo para que sepas su funcionamiento.
Gracias por todo y espero que sigas ayudando tanto y tan bien a los que nos iniciamos con android.

Responder
REVS 14/06/2012 - 17:26

Estimado, muchas gracias por tan buen tutorial. Necesito saber como hago para que mi aplicación se instale directamente en la SD o una manera que yo pueda especificar en que directorio de mi SD se instalará. Según tu experiencia será posible esto?

Responder
Rafalero 04/11/2012 - 17:00

Hola, estoy siguiendo el tutorial y es magnífico, he aprendido mucho y ya estoy haciendo mis primeras aplicaciones «decentes» jeje.
Me surge una duda. Mi programa usa muchos recursos multimedia como imágenes y sonidos… lo cual hace que tenga un tamaño considerable (unos 4mb) sin completarse sus contenidos. He leído que muchos móviles no tienen apenas memoria interna y no podrían soportar mi aplicación.
Mi pregunta es… ¿Sería posible instalar la aplicación en la SD y no en la memoria interna? De este modo se solucionaría el problema.
Si hay otra solución, también me gustaría aprenderla.

Muchas gracias!!

Responder
chencho 20/02/2013 - 13:07

Hola, muchas gracias por el aporte, quería comentarte que he leído en foros que la función Environment.getExternalStorageDirectory(); está obsoleta para la mayoría de android de versiones 4.0 o superiores, ya que del directorio raíz cuelgan dos directorios que son sdcard y extSdCard y hay que usar algo similar a File ruta_sd = new File(«/mnt/extSdCard/Ficheros»);

Pero vamos, he probado ambas y no hay manera de que pueda abrir el fichero contenido en la carpeta ficheros.

No sé si sabes algo más al respecto.

Muchas gracias por estos tutoriales !!!

Responder
Juan 02/05/2013 - 19:27

Se podria añadir texto a un archivo ya existente?

Me refiero a por ejemplo un archivo en la raiz de la SD que se llame «prueba.txt» y que contenga la palabra «Hola» y que en la aplicacion tengas un campo de texto que le pongas «mundo», y que al abrir el archivo tenga «Hola mundo» una vez guardado los datos, y asi susesivamente hasta que te canses de insertar texto…

Gracias.

Responder
Javitxu 06/05/2013 - 16:58

En primer lugar enhorabuena por el tutorial, y por el blog en general… Es uno de mis referentes a la hora de desarrollar.
En segundo lugar, quería hacer una pregunta:
Creo y leo ficheros en la sdcard de una Nexus7 sin problemas, o al menos sin problemas a la hora de programar, pero cuando intento acceder a esos ficheros creados a través del explorador de Windows, éstos nose ven, aunque sí existenpues lo compruebo con el ddms y mediante código JAVA.
Esto es algo que me han pedido en el curro y ando un tanto desesperado.

Gracias.

Responder
Ricardinho 09/02/2014 - 1:37

A mi me pasa exactamente lo mismo que a Javitxu, y tampoco lo he resuelto, pues igual le estaré trabajando y si doy con la respuesta acá mismo la coloco, muchas gracias por el curso esa muy muy bueno.

Responder
Ariel M 11/03/2014 - 20:00

Hola:
Estoy a la espera con la respuesta de si se puede o no hacer aplicaciones que se instalen en la memoria SD.

Agradeco su respuesta
Saludos !

Responder
sergio 01/04/2014 - 18:37

Respondiendo a juan , basta con ampliar los parámetros del constructor
OutputStreamWriter fout = new OutputStreamWriter( new FileOutputStream( f, true))) ;

Así si lo habrés dos veces primero escribes «Hola »
Segundo escribes «mundo»

Te aparecerá «hola mundo»

Espero haberte sido de ayuda Juan.

Responder
Alberto 30/04/2014 - 6:03

Esto es para poder usar archivos de textos, pero habrá un modo o un método para poder generar un archivo de audio a través del emulador??

De ser así, alguien me podría ayudar.

Gracias

Responder
miguel 15/07/2014 - 14:31

amigo como habro el terminal para poner los comandos?

Responder
kato 24/04/2015 - 1:47

Cordial Saludo.

Creo que hay una pequeña equivocación en cuanto al manejo que le están dando a la memoria.
En Android algunos dispositivos poseen una memoria propia que se divide en interna y externa. la interna es manejada por el sistema y solo la podemos acceder si somos root, la externa es accesible al usuario. Estas divisiones de memoria están en el equipo. La memoria SD no tiene nada que ver con estas memorias. El permiso en el manifest «android.permission.WRITE_EXTERNAL_STORAGE» hace referencia a la memoria externa del equipo y no a la tarjeta SD.
Si revisamos la gráfica del explorador observamos un árbol (estructura) que la podemos reconocer en todos los equipos y que corresponde a su memoria externa. La tarjeta SD presenta una estructura diferente para cada usuario. Por ultimo en la misma grafica cando se lee SD Card es de la abreviatura Standard Card y no la tarjeta SD.

Responder
Leticia 29/04/2015 - 8:29

Buenas.
Has hecho muy buenos tutoriales, gracias por compartirlo con nosotros!
Me gustaría que dedicases un capitulo a leer archivos guardados en la aplicación como un recurso, ya que lo estoy intentando hacer y me salen errores de compilación que no se solucionar.
Muchas gracias por compartir y un saludo!

Responder
Carlos 12/11/2015 - 1:10

los cursos de esta web estan bien completos, pero tengo una pregunta;
como puedo crear un directorio o carpeta desde la app en la memoria externa para guardar de ficheros que genere la misma app?

Responder
Luis Antonio M S 29/11/2016 - 23:15

Hola, Tengo una pregunta, es muy similar a lo que estas haciendo,mira te explico:

-Estoy haciendo una aplicacion en donde descargo un archivo de excel desde un repositorio utilizando como protocolo el sftp, este archivo es descargado en la carpeta de «downloads» de la memoria interna del celular, para lo que procede, es de que quiero es que la aplicacion sea capaz de poder buscar ese archivo que se depositó en la carpeta de download y depositarlo en una carpeta interna de la aplicacion para que esta pueda proceder a utilizarla.
-Alguien que pueda darme alguna idea de como poder realizarlo?, seria de gran ayuda! :D

Responder
Alejandro 13/01/2017 - 17:46

Buenas, estoy interesado en escribir un archivo con permisos, escribo el archivo de forma normal, pero cuando lo vayan a revisar no se pueda editar, seria mucho mejor si no lo pueden borrar, como puedo hacer esto? muchas gracias.

Responder
Alejandro 13/01/2017 - 17:58

ahora estoy necesitando ayuda en un problema, estoy escribiendo un archivo , después de escribirlo necesito dejarlo solo lectura que no pueda ser editado por el usuario, es mas si no puede eliminarlo me seria útil, ustedes conocen alguna forma donde puedo encontrar material de esto muchas gracias

Responder
Sergio 24/03/2017 - 19:52

Gran trabajo, ayudáis mucho.

No obstante, uno entra al hilo, creyendo que es posible escribir en la microSD (memoria externa, no interna).

¿Hay alguna forma de poder escribir en la externa (microSD) ó que pregunte al usuario y este al seleccionar con su explorador de archivos de sistema la microSD, el desarrollador pueda trabajar con la microSD?

Gracias de antemano.

Responder
Dalia Tovar 16/10/2017 - 0:58

Hola, tengo un problema al leer un archivo de la SD, me marca un error que no se encuentra el archivo en la carpeta, creo dicha carpeta en la SD y el file que quiero leer para ello ocupo lo siguiente:

File sd = Environment.getExternalStorageDirectory();

File file = new File(sd.getAbsolutePath(),filename );

sin embargo me marca que el archivo no se encuentra en dicha ruta, al realizar la practica, había funcionado correctamente pero me di cuenta que el archivo lo creo en mi almacenamiento interno de mi dispositivo y no en la tarjeta SD.

Dejaré mi código, me seria de gran ayuda sus comentarios, soy nueva en esto:

public class MainActivity extends AppCompatActivity {

GridView lista;
Button readFile;

//definimos nombre y ruta del archivo
private String filename = «cliente.txt»;
private String filepath=»/dulceria»;
File myExternalFile;
String myData =»»;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

lista = (GridView) findViewById(R.id.gridView);
readFile = (Button) findViewById(R.id.button);

}

public void CargarDatos (View view) throws IOException {

List list = new ArrayList();
String strLine ;

File sd = Environment.getExternalStorageDirectory();
File file = new File(sd.getAbsolutePath()+filepath,filename );

try {

FileInputStream fis = new FileInputStream(file);
InputStreamReader in = new InputStreamReader(fis);

BufferedReader reader = new BufferedReader(in);
if (in!= null) {
while ((strLine = reader.readLine()) != null) {

list.add(myData + strLine.split(«,»)[1]);
}
in.close();
}
} catch (IOException e) {
e.printStackTrace();

Log.e(«Ficheros»,»Error al leer fichero»);
Log.e(«Ruta»,»»+file);
}

Toast.makeText(this,»Cargados «+list.size(),Toast.LENGTH_LONG).show();

String datos[] = list.toArray(new String[list.size()]);
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, datos);
lista.setAdapter(adapter);

}

}

Responder
Nerina 21/11/2017 - 1:44

Hola ! Estoy intentando guardar un txt en memoria externa, me crea el directorio en la SD y todo, pero está vacío, el archivo nunca se genera, cuál puede ser el problema???

Responder

Responder a Desarrollo en Android | sgoliver.net blog Cancelar respuesta

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. Aceptar Más Información

Política de Privacidad y Cookies