Si la App que planteamos hace que el uso de SharedPreferences no sea una solución, siempre podríamos escribir y leer de un archivo de disco. Será algo más tedioso, pero tendremos mayor libertad.
Android usa un sistema de ficheros similar a los sistemas de ficheros de otras plataformas. Para trabajar con el sistema de ficheros de Android
usaremos la API java.io.*
Se usarán ficheros para guardar e intercambiar información a través de la red, o para trabajar con recursos como imágenes, audio y video.
Los sistemas Android siempre disponen de dos zonas de almacenamiento:
Almacenamiento interno
Es un almacenamiento no volátil, inherente al propio dispositivo y, por tanto, siempre disponible. Los ficheros guardados aquí sólo son accesibles por la aplicación que, se mantendrán hasta su desinstalación.
No es necesario ningún permiso para leer o escribir en la memoria interna si es en el directorio correspondiente a la aplicación.
El método getFilesDir() devuelve el directorio interno disponible para nuestra aplicación. Así, con la siguiente instrucción abriríamos un flujo de salida o de entrada según nos conveniese (FileOutputStream, FileInputStream).
File fich = new File(context.getFilesDir(), nombre_fichero);
También podríamos haber utilizado openFileOutput para obtener un FileOutputStream que escribe en un fichero del directorio interno de nuestra aplicación.
Si queremos usar ficheros temporales, nos podemos valer de getCacheDir() para obtener nuestro directorio interno temporal y de createTempFile para crear el fichero.
Almacenamiento externo
Se empezó a llamar así porque hacía referencia al almacenamiento en un medio extraíble (generalmente tarjeta SD).
Por este motivo, debemos entender que no siempre puede estar disponible (el usuario puede montar la tarjeta SD como almacenamiento USB para otro dispositivo...)
El acceso es practicamente global y todos pueden leer su contenido. Los permisos necesarios para su acceso son:
- WRITE_EXTERNAL_STORAGE es el permiso que hay que solicitar en el AndroidManifest para poder escribir en la memoria externa.
- READ_EXTERNAL_STORAGE es el permiso para leer de la memoria externa (aunque si se pide el permiso de escritura, implícitamente se tendrá permiso de lectura también).
Cuando el usuario desinstala, los ficheros almacenados aquí sólo se eliminan si están guardados en el directorio proporcionado por
getExternalFilesDir().
Como la memoria externa puede no estar disponible, siempre hay que comprabar su disponibilidad antes de hacer uso de ella mediante el método getExternalStorageState():
- si devuelve MEDIA_MOUNTED, la podemos usar en escritura y lectura,
- si devuelve MEDIA_MOUNTED_READ_ONLY sólo podemos leer.
getExternalStoragePublicDirectory nos devuelve el directorio en el que podemos guardar datos que permanecerán aunque la aplicación se desinstale. Estos datos serán accesibles para otras aplicaciones (públicos).
Al método anterior le pasamos una constante (p.ej: DIRECTORY_MUSIC) para categorizar los datos a guardar.
getExternalFilesDir nos devuelve un directorio externo en el que podemos almacenar datos “privados”, que se borrarán al desinstalar la aplicación.
El almacenamiento interno es la mejor opción cuando no queremos que otros usuarios o aplicaciones puedan acceder a los datos de nuestra aplicación.
Usaremos el almacenamiento externo para guardar datos que queremos compartir con otras aplicaciones o que queremos que permanezcan aunque la aplicación se desinstale (por ej, un archivo de música editado por nuestra aplicación...)
Por defecto las aplicaciones se instalan en el almacenamiento interno, pero este comportamiento se puede modificar con la propiedad android:installLocation en nuestro AndroidManifest.xml.
File dispone de los métodos getFreeSpace() y getTotalSpace() que nos indican respectivamente el espacio libre y el espacio total. Sin embargo, no tenemos garantizado poder escribir tantos bytes como nos devuelva getFreeSpace().
No estamos obligados a comprobar el espacio libre antes de escribir, podemos capturar una IOException si no podemos escribir por falta de espacio (a veces no sabemos el tamaño de los datos a escribir...)
Para eliminar ficheros, que ya no necesitemos, podemos utilizar el método delete() de File.
En el caso de tratarse de ficheros almacenados internamente, también podemos borrarlos llamando a: myContext.deleteFile(nombre_fichero)