Introducción a Node.js para principiantes

Módulo File System

En esta lección os voy a enseñar cómo trabajar con ficheros en Node utilizando el módulo File System.

En este módulo tenemos un montón de métodos para manejar ficheros y directorios, vamos a ver los más esenciales para empezar a trabajar, luego cada uno puede profundizar más por su cuenta dependiendo de lo que desee hacer.

app_fs.js

const fs = require('fs');

Lo primero que notaréis es que los métodos de este módulo se presentan en dos formas, la normal y otra con un Sync al final. Eso es porque están disponibles de forma no bloqueante por defecto (asíncrona) o bloqueante (síncrona).

¿Recordáis la función setTimeout? Pues con los métodos asíncronos pasa lo mismo, se ejecutan sin bloquear el resto del programa.

Esto es importante porque normalmente estas tareas suelen ser bloqueantes debido a que, aunque sepas cuándo abres el fichero, no sabes cuanto se tardará en leer o escribir su contenido, depende de varios factores, como la rapidez de la memoria o el propio tamaño del fichero. Al hacerlo de forma asíncrona no tenemos este problema y todo se sigue ejecutando independientemente de cuanto tarden en manipularse los ficheros, es un escenario ideal.

¿Y entonces porqué se incluyen las formas síncronas? Pues por conveniencia, porque quizá en algunos escenarios sí es conveniente detener la ejecución, pero creedme que no es lo normal.

Aún así vamos a realizar un ejemplo de código que lea el contenido de un directorio de ambas formas para que entendáis la diferencia con la práctica.

Para leer el contenido de un directorio, es decir los ficheros que hay dentro se utiliza el método readdir, éste devuelve un arreglo con los ficheros.

Hagámoslo primero de forma bloqueante:

const files = fs.readdirSync('./');
console.log(files);

console.log("Fin del progama")

Como véis obtenemos el arreglo con los ficheros. Si quiséramos recorrerlos uno a uno podríamos usar el método forEach de las colecciones tal como expliqué en el curso del conversor de divisas:

const files = fs.readdirSync('./');
files.forEach(file => {
    console.log(file);
});

Ahora vamos a la versión asíncrona, su peculiaridad es que su resultado se devuelve a una función callback de retorno que se llamará cuando se haya ejecutado el método, exactamente igual como funciona el setTimeout pero sin el temporizador, con la diferencia que la función requiere un parámetro para almacenar posibles errores si no se lee bien el directorio, y otro con los ficheros encontrados:

// const files = fs.readdirSync('./');

fs.readdir('./', function (err, files) {
	files.forEach(file => {
	    console.log(file);
	});
});

Si lo ejecutamos devolverá el mismo resultado, pero lo interesante es que veremos el mensaje Fin del programa antes de que se lea el contenido del directorio.

Una mejor implementación de este código haciendo uso del error sería uso de una condición if (sí en español) para comprobar si err tiene algún valor y en caso contrario, si todo está correcto, usar la contra condición else (sino en español) y mostrar los ficheros:

fs.readdir('./', function (err, files) {
	if (err) {
		console.log("Ocurrió un error", err);
	} else {
		files.forEach(file => {
		    console.log(file);
		});
	}
});

Si provocamos manualmente un fallo, por ejemplo poniendo un directorio que no existe, veremos como nos muestra el fallo que ha ocurrido.

Sea como sea con este ejemplo seguro que os queda un poco más clara la diferencia entre código bloqueante y código no bloqueante que hemos venido comentando desde el principio del curso.

Os recomiendo echar un vistazo a los métodos readFile y writeFile para leer y escribir ficheros, mirad los ejemplos de la documentación y no tengáis miedo de experimentar.