Sistema de ficheros (fs)

Trabajar con ficheros en el sistema


Antes de meternos en algún proyecto más avanzado con Node, vamos a aprender a leer ficheros de texto utilizando la API fs de NodeJS. Como siempre, la importaremos utilizando node:fs y utilizaremos un método llamado readFile.

Vamos a comenzar teniendo en cuenta que tenemos un fichero llamado file.txt que contiene varias líneas de texto con una frase en cada una.

El método readFile / readFileSync

En NodeJS podemos utilizar dos formas de leer un fichero, readFile (versión asíncrona) y readFileSync (versión síncrona). Aquí puedes ver un ejemplo sencillo que lee el contenido del fichero de texto:

// Utilizamos readFile (asíncrono)

import { readFile } from "node:fs/promises";
import { styleText } from "node:util";

const FILE = "./file.txt";

const fileContent = await readFile(FILE, { encoding: "utf-8" });
const lines = fileContent.trim().split("\n");

console.log(styleText("magenta", "El contenido del fichero:"));
console.log(lines);
// Utilizamos readFileSync (síncrono)

import { readFileSync } from "node:fs";
import { styleText } from "node:util";

const FILE = "./file.txt";

const fileContent = readFileSync(FILE, { encoding: "utf-8" });
const lines = fileContent.trim().split("\n");

console.log(styleText("magenta", "El contenido del fichero:"));
console.log(lines);

Observa que al usar readFile() le pasamos la ruta del fichero, así como un objeto de opciones donde le indicamos la codificación del fichero (generalmente, utf-8). En la siguiente línea hacemos un trim() para eliminar los espacios sobrantes al principio o final del texto.

Finalmente, dividimos el contenido por cada línea, separando por \n, es decir, por los saltos de línea (ENTER), y los mostramos por pantalla.

Observa las diferencias de la versión síncrona, que se llama readFileSync() y la versión asíncrona, donde se usa await y se importa de node:fs/promises.

Aunque tenemos un método asíncrono readFile en node:fs, funciona mediante callbacks, y hoy en día, lo ideal sería utilizar el readFile asíncrono de node:fs/promises, ya que tiene integración con promesas y es mucho más cómodo.

De la misma forma que tenemos un readFile() y un readFileSync(), también tenemos un writeFile() y un writeFileSync() que funcionan de forma muy parecida y siguen la misma lógica. En este caso, el primer parámetro es la ruta del fichero, el segundo parámetro es el contenido que quieres guardar en el fichero, y el tercero es el objeto de opciones.

El método readdir()

Con el método readdir() podemos leer los archivos (y carpetas) que contiene una ruta indicada. Dicha ruta la obtenemos con el método cwd(), que nos devuelve la ruta actual donde nos encontramos al ejecutar el programa.

El método readdir() nos devuelve un array de con los archivos y carpetas de la ruta, en el segundo parámetro podemos indicarle un valor recursive para que revise las subcarpetas interiores y withFileTypes para que devuelva un objeto con partes separadas en lugar de un :

import { cwd } from "node:process";
import { readdir } from "node:fs/promises";
import { styleText } from "node:util";

const CURRENT_PATH = cwd();
const files = await readdir(CURRENT_PATH, {
  recursive: false,
  withFileTypes: true
});

const getIcon = (entry) => {
  if (entry.isDirectory()) return "📁";
  else if (entry.isFile()) return "📄";
  else return "❓";
}

console.log(styleText("magenta", `El contenido de la carpeta`), ":");
console.log(CURRENT_PATH);

files.forEach((entry) => {
  const icon = getIcon(entry);
  const { name } = entry;

  console.log(styleText("yellow", "- "), `${icon} ${name}`);
});
$ node index.js
El contenido de la carpeta: /home/manz/node-examples/fs-promises
-  📄 index.js
-  📄 jsconfig.json
-  📁 node_modules
-  📄 package.json
-  📄 pnpm-lock.yaml
-  📁 scripts

Al final del código, observa que hacemos un forEach de files obteniendo un icono y un nombre, extraído de cada entrada de readdir(). Observa que el método getIcon() utiliza métodos como .isDirectory() o .isFile() para saber si es un fichero o una carpeta. Con .name obtenemos el nombre del fichero y con .path obtenemos la ruta, entre otras cosas.

El método lstat()

Si necesitamos más información de un fichero o carpeta, podemos utilizar el método lstat(). Por ejemplo, podemos obtener el tamaño del fichero con .size o la fecha de modificación con .mtime. En este fragmento de código, obtenemos esa información en la constante stat, y los mostramos por pantalla en forma de columna:

import { cwd } from "node:process";
import { readdir, lstat } from "node:fs/promises";
import { styleText } from "node:util";

const CURRENT_PATH = cwd();
const files = await readdir(CURRENT_PATH, { recursive: false, withFileTypes: true });

console.log(styleText("magenta", `El contenido de la carpeta`), `: ${CURRENT_PATH}`);
const RTF = new Intl.RelativeTimeFormat("es-ES");

files.forEach(async (entry) => {
  const stat = await lstat(`${entry.path}/${entry.name}`);

  const sizes = [20, 30, 15];
  const colors = ["white", "yellow", "green"];
  const columns = [entry.name, stat.mtime.toISOString(), stat.size + " bytes"];

  const line = [];
  columns.forEach((column, index) => {
    line.push(styleText(colors[index], column.padStart(sizes[index], " ")));
  });
  console.log(...line);
});`
El contenido de la carpeta : /home/manz/node-examples/fs-promises
            index.js       2024-06-25T19:14:52.614Z       800 bytes
       jsconfig.json       2024-06-25T12:51:32.470Z         3 bytes
        node_modules       2024-06-25T12:50:16.020Z      4096 bytes
        package.json       2024-06-25T12:50:16.020Z       240 bytes
      pnpm-lock.yaml       2024-06-25T12:50:16.020Z        93 bytes
             scripts       2024-06-25T16:36:37.346Z      4096 bytes

Otros métodos interesantes

Existen muchos otros métodos que pueden resultar interesantes, relacionados con el sistema de ficheros y carpetas. Por ejemplo, aquí algunos:

Método Descripción
access() Comprueba si tenemos permiso sobre ese fichero o carpeta.
appendFile() Añade información a un fichero que ya existe o inexistente.
chmod() Cambia los permisos de un fichero.
chown() Cambia el propietario de un fichero.
cp() Copia un fichero a una ruta específica.
glob() Busca los archivos que coincidan con un patrón dado.
link() Crea un enlace simbólico a un fichero o carpeta existente desde otra ruta.
mkdir() Crea una carpeta nueva.
realpath() Devuelve la ruta real de un fichero, generalmente de un enlace simbólico.
rmdir() Elimina una carpeta.
rm() Elimina ficheros o carpetas/directorios.
unlink() Elimina un fichero.
watch() Vigila cambios en ficheros o carpetas.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev