En este Tutorial Swift aprenderemos sobre el manejo de archivos y carpetas. Recordemos que Swift es un lenguaje de propósito general y como tal no está atado a un solo dispositivo o sistema operativo, aunque usualmente se le asocie con el desarrollo de aplicaciones móviles también podemos crear aplicaciones para macOS.

No podemos decir que dominamos un lenguaje cuando solamente creamos código para una plataforma. Clic para tuitear

Por esta razón en el artículo de hoy estaremos enfocados en macOS, aunque la mayoría de estas instrucciones también son compatibles con iOS. Todos los códigos que aquí se muestran han sido probados en una aplicación de consola pero sería similar en una aplicación Cocoa.

A continuación veremos ejemplos prácticos de acciones que con cierta frecuencia necesitamos ejecutar sobre archivos y directorios.

Creando un Archivo

En el manejo de archivos y carpetas el papel protagónico se lo lleva la clase FileManager, con esta podemos lograr casi todo cuanto necesitemos. Veamos como crear un archivo:

Comenzamos con dos líneas en las cuales declaramos dos constantes de tipo URL y donde definimos las dos carpetas con las que trabajaremos durante estos ejemplos. Junto a estas tenemos otra constante de tipo URL donde definimos el fichero que crearemos y que también utilizaremos para el resto de ejemplos. En la línea 16 definimos una cadena de nombre stringLine que constituye una representación de los datos que pudiéramos pasar al archivo que crearemos. Seguido a esta tenemos una constante de tipo Data y de nombre dataToFile. Sobre esta llamamos a la función String.data que nos devuelve una representación de los datos de la constante stringLine codificados en este caso con UTF8. En la línea 20 creamos una instancia de la clase FileManager, que luego usamos en la siguiente para ejecutar el método createFile:

Como primer parámetro pasamos el nombre de nuestro archivo, en el segundo parámetro pasamos los datos a escribir en el archivo aunque de esto no ser un requerimiento, podemos escribir nil, mientras que en el tercero especificamos los atributos de creación o apertura del archivo.

Los atributos disponibles son los siguientes:

Atributo

Descripción

static let appendOnly: FileAttributeKey

Este valor indicaría si se encuentra en solo lectura o no.
 static let type: FileAttributeKeyEste valor indica el tipo de archivo.

static let busy: FileAttributeKey

Este valor indica si el archivo se encuentra en uso.

static let creationDate: FileAttributeKey

Este valor indica la fecha de creación del archivo.

static let ownerAccountName: FileAttributeKey

Este valor indica el nombre de usuario al que pertenece el archivo.

static let groupOwnerAccountName: FileAttributeKey

Este valor indica el nombre del grupo al que pertenece el usuario propietario del archivo.

static let deviceIdentifier: FileAttributeKey

Este valor nos muestra el identificador del dispositivo donde reside el archivo.

static let extensionHidden: FileAttributeKey

Este valor indica si la extensión del archivo se encuentra oculta o no.

static let groupOwnerAccountID: FileAttributeKey

Este valor indica el ID del grupo al que pertenece.

static let hfsCreatorCode: FileAttributeKey

Este valor indica el código HFS asociado a la creación del archivo.

static let hfsTypeCode: FileAttributeKey

Este valor indica el código HFS asociado al tipo del archivo.

static let immutable: FileAttributeKey

Este valor indica si el archivo es mutable o no, es decir si este se puede modificar.

static let modificationDate: FileAttributeKey

Este valor indica la última fecha de modificación.

static let ownerAccountID: FileAttributeKey

Este valor nos muestra el ID del usuario propietario del archivo.

static let posixPermissions: FileAttributeKey

Este valor indica los permisos (Posix) del archivo.

static let referenceCount: FileAttributeKey

Este valor indica el conteo de referencia que posee en archivo.

static let size: FileAttributeKey

Este valor indica el tamaño del archivo en bytes.

static let systemFileNumber: FileAttributeKey

Este valor indica el número de archivo en el sistema de archivos.

static let protectionKey: FileAttributeKey

Este valor indica el nivel de protección de este archivo.

Es ejecutable?

Otra acción que es bien útil es aquella donde comprobamos si un archivo es ejecutable o no. Veamos:

Aquí todo se logra en una línea, en la primera, que es donde ejecutamos el método isExecutableFile de nuestra instancia fileManager, al cual pasamos como parámetro la dirección del archivo que creamos en el anterior ejemplo.

Es Modificable?

Esta pregunta tiene que estar siempre implícita en nuestra mente cuando nos encontramos trabajando con el sistema de archivos.

Antes de escribir en un archivo siempre es recomendable verificar si este puede ser modificado. Clic para tuitear

Esto puede estar determinado ya sea por permisos de usuario o porque fue abierto como solo lectura.

Al igual que el ejemplo anterior todo se logra en una línea, en este caso a través del método isWritableFile al cual se le pasa el parámetro del archivo en cuestión.

¿Cómo copiar o mover un archivo?

La copia de un archivo es posiblemente una de las acciones más frecuentes que un usuario lleva a acabo en su día a día con un ordenador. Esto en el lenguaje de programación Swift lo podemos lograr de la siguiente manera:

Tanto la copia como el movimiento de un archivo son acciones que pueden generar un error, por eso la llamada al método copyItem y a moveItem se ejecuta a través de try y se encierran dentro de un bloque do-catch. Creo que lo más significativo de este ejemplo es el método appendingPathComponent que forma parte de URL y que nos permite concatenar momentáneamente el texto especificado.

Otra funcionalidad relacionada con este ejemplo sería la de renombrar un archivo, en este caso solamente tendríamos que ejecutar moveItem sobre el mismo directorio y especificar el nuevo nombre en el parámetro toPath.

Atributos de los archivos

Todos los archivos cuentan con atributos, estos pueden ser tanto el nombre de usuario propietario del mismo así como el grupo al que pertenece, fecha de creación o última modificación, el tamaño, los permisos, etc.

El método attributesOfItem nos devuelve un arreglo de tuplas donde podremos encontrar el atributo junto al valor de este. La lista completa de atributos la podemos encontrar en la tabla que hemos mostrado al inicio de este tutorial.

¿Cómo eliminar un archivo?

Después de crear y copiar un archivo también es necesario saber como eliminarlo. Veamos como lograrlo:

Al igual que cuando copiamos un archivo, al eliminarlo efectuamos la llamada, en este caso al método removeItem, haciendo uso de la instrucción try y manejando el posible error con un bloque do-catch.

Creando una carpeta

Llegó el turno a las carpetas así que comencemos por crear una:

Aquí vemos que el patrón es el mismo que hemos seguido hasta ahora, siempre haciendo uso de FileManager y en esta ocasión el método createDirectory.

Eliminando una carpeta

En el caso de querer eliminar una carpeta pues seguimos los mismos pasos que hemos efectuado cuando eliminamos un archivo:

No hay mucho que agregar, los archivos y las carpetas son tratados de la misma forma.

Obtener directorio actual

Cuando necesitamos el directorio actual, si esto no está relacionado con una tarea que estamos realizando con un directorio especificado por el usuario, pues usualmente hablamos del directorio donde se encuentra la aplicación, el binario de la misma.

Contenido de una carpeta

Listemos ahora el contenido de un directorio:

Este ejemplo es un poco más extenso ya que tenemos que iterar sobre la lista de elementos que nos devuelve el método contentsOfDirectory y que almacenamos en la constante files.

Directorio temporal

Los que tenemos experiencia en sistemas Unix sabemos de la existencia de la carpeta /tmp donde el sistema y sus demonios establecen sus archivos temporales. Pues esto también se puede convertir en una necesidad para nosotros, veamos como lograrlo:

Leyendo un archivo

Ahora leamos el texto de un archivo, una acción que no podemos dejar de comentar:

Lo primero que hacemos es crear una constante de nombre file y que funge como instancia de la clase FileHandle. Para no irnos del tema, pudiéramos decir que esta clase viene a facilitarnos el manejo de archivos permitiéndonos leer, escribir y buscar.

La clase FileHandle nos permite acceder a un archivo, un socket, una tubería o un dispositivo. Clic para tuitear

En la línea siguiente comprobamos si file no es igual a nil caso en el que no se pudo acceder al archivo de manera satisfactoria. Asumamos que sí y saltemos a la línea 5 donde almacenamos en la constante data el retorno del método readDataToEndOfFile cuyo nombre lo dice todo, con esta llamada leemos de manera sincrónica todos los datos contenidos en este archivo desde el inicio hasta el final. En la línea 7 cerramos el acceso a nuestro fichero ya que todo su contenido ya fue leído. Luego en la 9 convertimos estos datos al tipo String para terminar imprimiéndolos en la línea 11.

Ahora, en caso de que no necesitemos tantas funcionalidades como las que nos brinda FileHandle y nos valdría con solamente poder leer los datos del archivo y almacenarlo en una constante / variable String. De ser así el siguiente código sería una alternativa suficiente:

Escribir hacia un archivo

La vía para escribir hacia un archivo es muy similar al proceso de lectura. Para mostrar este proceso vamos a unir el ejemplo anterior con el que corresponde a este apartado.

En este código leemos los datos que tenemos en el archivo “texto-a-leer.txt”, almacenaremos estos en nuestra variable de tipo Data para luego escribirlos en el archivo de nombre “texto-a-escribir.txt”.

Espero que todo cuanto se ha dicho aquí, de una forma u otra le haya servido de aprendizaje, de referencia, que haya valido su preciado tiempo.

Este artículo, al igual que el resto, será revisado con cierta frecuencia en pos de mantener un contenido de calidad y actualizado.

Cualquier sugerencia, ya sea errores a corregir, información o ejemplos a añadir será, más que bienvenida, necesaria!