El sistema de archivos
Last updated
Was this helpful?
Last updated
Was this helpful?
En iOS el sistema de archivos al completo no es visible para una aplicación cualquiera ya que por motivos de seguridad está contenida en lo que se denomina un sandbox. Una aplicación solo puede acceder a los archivos y directorios dentro de su sandbox, y a la inversa otras aplicaciones no pueden acceder a ellos.
El sandbox tiene una estructura de directorios estandarizada, donde cada directorio tiene un papel específico reservado en la aplicación. Nuestra aplicación puede crear y modificar libremente archivos y directorios, aunque siempre debería respetar el papel que el sistema le asigna a cada directorio.
Primero veremos cuál es la estructura “estándar” del sandbox y luego el API para abrir, crear y modificar archivos y directorios.
Cuando se instala una aplicación en un dispositivo iOS el sistema crea una estructura de directorios como la que aparece en la siguiente figura.
Los directorios más importantes son los siguientes:
nombre_de_la_aplicacion.app/
: aunque por la extensión podría parecer que es un archivo se trata de un directorio, que contiene lo que se denomina el bundle de la aplicación: el ejecutable, los iconos, imágenes, sonidos, etc.
Documents/
: es el directorio reservado para el contenido creado por el usuario. Si por ejemplo nuestra aplicación es un editor de textos, aquí es donde deberíamos almacenarlos.
Library/
: no suele contener directamente archivos sino solamente dos subdirectorios:
Caches/
: donde almacenamos los datos que se pueden volver a recrear sin problemas si es necesario. Por ejemplo índices de datos de nuestra aplicación que sirvan para hacer las búsquedas más rápidas. Por ello iOS no hace copia de seguridad de este directorio cuando hacemos un backup del dispositivo.
Preferences/
: las preferencias de configuración de la aplicación, que posteriormente veremos con más detalle.
Application Support/
: contenido generado por la aplicación pero que no ha sido creado directamente por el usuario.
tmp/
: como es lógico está reservado a archivos y directorios temporales, de los que iOS tampoco hará copia de seguridad.
Antes de poder realizar cualquier operación sobre un archivo o directorio, tenemos primero que localizarlo en el sistema de archivos, es decir, encontrar su path absoluto - desde la raíz del sistema de archivos. Aunque en iOS no podemos “salirnos fuera” del sandbox este paso sigue siendo necesario.
En iOS podemos dar cualquier trayectoria de un archivo de dos formas distintas: como path local (un String
) o como URLs, que uniformizan el tratamiento de las rutas y nos permite también especificar la localización de recursos remotos. En Foundation las URLs se representan mediante un tipo especial, URL
. Los nombres de los métodos que trabajan con paths generalmente acaban en Path
y ocurre lo propio con los que trabajan con URLs (que, lógicamente, acaban en URL
).
En la documentación oficial de iOS Apple recomienda usar URLs en lugar de paths, ya que uniformizan el tratamiento de los recursos, sean locales o no.
La clase básica que se usa para interactuar con el sistema de archivos es el FileManager
. No es necesario crear una instancia, podemos obtener la instancia por defecto con FileManager.default
Acceder al directorio con el bundle de la aplicación (el .app
) es sencillo:
Ya hemos visto antes este tipo de código cuando accedíamos a imágenes y otros archivos distribuidos junto a la aplicación.
Con bundleURL
en lugar de bundlePath
podemos obtener también el path en forma de URL (Un objeto de la clase URL
).
Para obtener la URL de un directorio del sandbox se usa el método urls(for:in:)
, de la clase FileManager
. Al método le pasamos un par de constantes:
El "dominio" o ámbito de la búsqueda, un valor enumerado del tipo FileManager.SearchPathDomainMask
. En iOS siempre usaremos el valor userDomainMask
, que en OSX indica el directorio del usuario, pero en iOS en realidad se refiere al ámbito de la aplicación actual.
Por ejemplo, así obtendríamos la URL del directorio Documents
de la aplicación actual:
Si ejecutamos el código anterior en un dispositivo real nos aparecerá una URL del estilo file:///var/mobile/Containers/Data/Application/id_de_la_aplicacion/Documents
.
En el simulador la URL será similar pero la primera parte de la trayectoria cambia ya que se refiere a donde se está ejecutando la app dentro del simulador, algo como file:///Users/[nombre_usuario]/Library/Developer/CoreSimulator/Devices/[id_del_dispositivo]/data/Containers/Data/Application/[id_de_la_aplicacion]/Documents/
. Para complicar un poco más el asunto, el identificador de la app cambiará cada vez que pongamos en marcha el simulador.
Podemos obtener el path del directorio para archivos temporales con la propiedad temporaryDirectory
del file manager
Donde el id de la aplicación incluye no solo el nombre de la aplicación sino también el identificador del desarrollador (el id de la aplicación es lo que aparece en la configuración del proyecto, apartado General
, con el nombre Bundle Identifier
)
Sabiendo la URL de un determinado directorio podemos listar sus contenidos con el método contentsOfDirectory(at:includingPropertiesForKeys:options:)
El siguiente ejemplo toma el directorio donde está el bundle de la aplicación y lista sus contenidos, mostrando para cada elemento la fecha de creación y si es o no un directorio.
El parámetro includingPropertiesForKeys
es un array de constantes de la clase URLResourceKey
donde especificamos la "meta-información" a obtener para cada item (por ejemplo tamaño, fecha de creación, si es o no un directorio, etc).
options
puede ser 0 o bien .skipsHiddenFiles
para indicar que no queremos obtener los archivos o directorios ocultos.
Una vez obtenemos los items con contentsOfDirectory
, mostramos sus datos, incluyendo la información obtenida. La "meta-información" sobre el archivo/directorio se obtiene con el método de la clase URL
llamado resourceValues
. Este nos devuelve un objeto URLResourceValues
con propiedades que se corresponden con los datos de la "meta-información"
Una versión simplificada del listado de directorios nos la da el método contentsOfDirectory(atPath:)
que trabaja a partir de un path en forma de String
y no permite obtener propiedades de los items, solo nos devuelve array de String
con los nombres.
La clase de directorio que estamos buscando, como un valor enumerado del tipo FileManager.SearchPathDirectory
(por ejemplo para Library/
el valor es libraryDirectory
, para Documents
es documentDirectory
y para Cache
, cachesDirectory
). Se puede consultar la , aunque la mayoría de valores solo tienen sentido en OSX.
Durante el desarrollo en el simulador puede ser necesario localizar físicamente los directorios de la aplicación en el disco para poder verificar las operaciones sobre archivos y directorios. Para ayudarnos en esta tarea podemos usar alguna utilidad de terceros como la aplicación . Esta aplicación es comercial, pero también existen aplicaciones libres como . Otra opción, más tediosa, es usar la herramienta simctl
. En una terminal escribir: