2.1 · Módulos nativos: fs, path, os

Nivel 2 · Núcleo de Node.js

2.1Módulos nativos: fs, path, os

Objetivo: Aprovechar los módulos nativos de Node (fs en asíncrono, path portable, os): las capacidades del sistema sin dependencia externa.
Tiempo estimado: 11 min · lectura autónoma · Si solo tienes 5 min: lee «Lo esencial en 30s» + el esquema.

Lo esencial en 30 segundos

  • Integrados, sin instalación: fs, path, os vienen con Node y se importan por su nombre — menos dependencias, más ligero, más seguro.
  • fs = asíncrono por defecto: fs.promises + await no bloquea el bucle de eventos — el Sync bloquea el servidor para todos.
  • path aporta portabilidad, os informa: path.join gestiona el separador correcto en cada sistema, os expone plataforma y memoria — nunca rutas concatenadas a mano.

Minicaso hilado — Salim hace el inventario de los informes en Argel

Salim, desarrollador junior en Argel, debe equipar a su equipo: cada semana, decenas de informes de texto llegan a una carpeta compartida, y hay que registrarlos (nombre, tamaño, fecha) en un archivo de inventario. Escribe su primer script Node sin instalar nada: fs lee y escribe los archivos, path construye rutas que funcionan tanto en su Windows como en el servidor Linux del equipo, os muestra la plataforma para el registro. Este mismo proyecto vuelve en 2.2 (señalar el progreso con eventos), 2.3 (informes grandes tratados en stream) y 2.4 (servir el inventario por HTTP).

Hilo conductor del nivel 2: este mismo proyecto de Salim vuelve en el curso, el esquema, el script y el desafío 48h — y continúa en 2.2, 2.3 y 2.4.

1. Módulos nativos, sin instalar nada

Node proporciona módulos nativos (built-in): bibliotecas integradas, disponibles sin instalar nada, que dan acceso a las capacidades del sistema — archivos, red, sistema operativo. Esto es lo que hace de Node mucho más que un simple ejecutor de JavaScript. Se importan por su nombre solo (require('fs'), con el prefijo explícito node: posible: require('node:fs')). El más usado es fs (file system): leer, escribir, modificar, eliminar archivos y carpetas. El interés es doble: cubrir las necesidades comunes sin dependencia externa y comprender el fundamento de las bibliotecas (Express se basa en el módulo http). Salim lo comprobó: su inventario no requiere ningún paquete npm.

2. fs: lo asíncrono primero, lo Sync casi nunca

Punto crucial: la mayoría de las funciones de fs existen en dos versiones — asíncrona (no bloqueante, preferible: fs.readFile con callback, o mejor fs.promises.readFile con await) y síncrona (bloqueante, con sufijo Sync: fs.readFileSync). En servidor, se usa lo asíncrono para no bloquear el bucle de eventos: un solo readFileSync lento congela el servidor para todos los clientes. Lo síncrono solo se justifica en casos precisos — pequeños scripts puntuales, carga de configuración al arranque. Salim escribe pues su inventario en fs.promises + async/await: moderno, legible, no bloqueante.

3. path para la portabilidad, os para el sistema

El módulo path manipula las rutas de forma portable: el separador es / en macOS/Linux pero \ en Windows, por eso nunca se monta una ruta a mano. path.join(__dirname, 'data', 'fichier.txt') usa el separador correcto según el sistema; path.resolve() da una ruta absoluta, path.basename(), path.extname() y path.dirname() extraen sus partes. El módulo os expone el sistema: os.platform(), os.cpus() (útil para el clustering, sección 5-2), os.totalmem() / os.freemem(), os.homedir(), os.tmpdir(). Existen otros nativos (crypto, util, url…): no hace falta memorizarlos todos, pero hay que saber que existen y consultar la documentación oficial.

Error frecuente de interpretación: «Para ir rápido, uso las versiones Sync en todas partes — es más fácil de leer». No. En un servidor, cada llamada síncrona bloquea el único hilo de Node durante toda la operación: mientras readFileSync lee un archivo, el servidor no responde a ningún otro usuario. Lo «más simple» aparente es un grave fallo de rendimiento en cuanto hay clientes simultáneos. La regla: en servidor, siempre lo asíncrono (fs.promises + await); lo Sync está reservado a pequeños scripts puntuales y a la carga de configuración al arranque.
Los tres nativos del día a día Sistema sin dependencia fsLeer/escribir en asíncrono (promises + await)+pathRutas portables (join, resolve, basename)+osInformación del sistema (plataforma, CPU, memoria) Nativos = importados por su nombre, cero instalación.
Sistema sin dependencia
Versión en texto del esquema (SEO / lectores de pantalla / traducción): 1) Salim importa los NATIVOS por su nombre (require('fs'), require('path'), require('os')) — nada que instalar. 2) Lee y escribe el inventario con fs.promises + await: ASÍNCRONO, el servidor sigue reactivo para todos. 3) Monta las rutas con path.join: PORTABLES entre su Windows y el Linux del equipo. 4) Registra la plataforma y la memoria con os. Lección: los nativos cubren las necesidades comunes sin dependencia — y fundamentan bibliotecas como Express.

🔎 Ejemplo concreto — 🔎 Ejemplo concreto — El inventario de Salim en asíncrono

Tres nativos combinados, como en el script de Salim:

const fs = require('node:fs/promises');
const path = require('node:path');
const os = require('node:os');

const dossier = path.join(__dirname, 'rapports');
const fichiers = await fs.readdir(dossier);
const inventaire = path.join(dossier, 'inventaire.txt');
await fs.writeFile(inventaire, fichiers.join('\n'));
console.log('Plateforme :', os.platform());

Lectura: ningún paquete instalado, rutas portables, escritura no bloqueante.

Lección: fs.promises + await en servidor, Sync reservado a los scripts.

Vocabulario de la sección

Módulos nativos (built-in)
Bibliotecas integradas en Node, importadas por su nombre sin instalación: fs, path, os, http, crypto, events, stream…

Ejemplo sencillo: Salim importa fs, path y os sin tocar npm.

Lo que no es: un paquete npm de terceros que hay que instalar y actualizar.

Reflejo: necesidad común = comprobar lo nativo antes de instalar.

fs (file system)
Módulo de lectura/escritura de archivos y carpetas, en versión asíncrona (preferible, fs.promises + await) o síncrona (Sync, bloqueante).

Ejemplo sencillo: Salim registra los informes con fs.readdir y fs.writeFile.

Lo que no es: un módulo de enrutamiento web (es Express, nivel 3).

Reflejo: archivos en servidor = fs.promises + await.

Asíncrono vs síncrono (fs)
Lo asíncrono (no bloqueante) deja a Node atender otras peticiones durante la operación; lo síncrono (Sync) bloquea el único hilo.

Ejemplo sencillo: El inventario de Salim se escribe sin congelar el servidor.

Lo que no es: dos sintaxis intercambiables sin consecuencias.

Reflejo: servidor = asíncrono; Sync = scripts y configuración al arranque.

path
Módulo de manipulación portable de rutas (join, resolve, basename, extname, dirname) que gestiona el separador de cada sistema.

Ejemplo sencillo: path.join(__dirname, 'rapports') funciona en el Windows de Salim y en el Linux del equipo.

Lo que no es: una concatenación a mano con barras en duro.

Reflejo: una ruta que construir = path.join.

os
Módulo de acceso a la información del sistema: plataforma, procesadores (os.cpus), memoria, carpetas estándar (homedir, tmpdir).

Ejemplo sencillo: Salim registra os.platform() y os.freemem() con su inventario.

Lo que no es: un módulo de lectura de archivos.

Reflejo: información de la máquina (clustering, diagnóstico) = pensar en os.

En la práctica — En la práctica — Utilizar los módulos nativos

  1. Lea y escriba un archivo con fs.promises y async/await (versión asíncrona, no bloqueante); compare con fs.readFileSync (síncrona, bloqueante).
  2. Construya rutas portables con path.join(__dirname, 'dossier', 'fichier.txt') en lugar de concatenar a mano.
  3. Extraiga información de una ruta: path.basename, path.extname, path.dirname.
  4. Muestre información del sistema con os: os.platform(), os.cpus().length, os.freemem().
Aprovecha los módulos nativos de Node (fs para los archivos en asíncrono, path para las rutas portables, os para el sistema) — las capacidades del sistema sin dependencia externa.

Script listo para decir — justificar lo todo-nativo ante su responsable (30 s)

«Para el inventario de informes, no instalé nada: fs lee y escribe los archivos en asíncrono con fs.promises, path construye rutas que funcionan en Windows como en Linux, y os registra la plataforma. Cero dependencias, por tanto cero actualizaciones que seguir — y son los mismos bloques sobre los que está construido Express.»

Para decir mostrando el script funcionando en ambos sistemas; el argumento que convence es la ausencia de dependencia.

Modelo copiar-pegar — inventario de carpeta en asíncrono

const fs = require('node:fs/promises');
const path = require('node:path');
const os = require('node:os');

async function inventaire(nomDossier) {
  const dossier = path.join(__dirname, nomDossier);
  const fichiers = await fs.readdir(dossier);
  const lignes = [];
  for (const f of fichiers) {
    const chemin = path.join(dossier, f);
    const stats = await fs.stat(chemin);
    lignes.push(f + ' | ' + stats.size + ' octets | ' + path.extname(f));
  }
  const sortie = path.join(dossier, 'inventaire.txt');
  await fs.writeFile(sortie, lignes.join('\n'));
  console.log('Inventaire écrit sur', os.platform(), ':', sortie);
}

inventaire('rapports').catch(console.error);

Script personal rápido

Una pequeña utilidad puntual (renombrar, ordenar archivos): lo Sync es aceptable, el script termina enseguida.

Equipo mixto Windows/Linux

Salim destierra las barras en duro: toda ruta pasa por path.join para funcionar en todas partes sin retoques.

Servidor en producción

fs.promises + await en todas partes: ninguna llamada Sync en la ruta de las peticiones, el bucle de eventos queda libre.

Diagnóstico de máquina

Antes de desplegar, os.cpus().length y os.freemem() calibran el dimensionamiento (ver clustering, sección 5-2).

✓ Buenas prácticas

  • Importe los nativos por su nombre (prefijo node: posible) sin instalar nada.
  • Use fs.promises + await en servidor; reserve lo Sync a los scripts y a la configuración.
  • Construya cada ruta con path.join, nunca por concatenación.

✗ Errores frecuentes

  • Usar las versiones Sync en un servidor (bloqueo para todos los clientes).
  • Concatenar las rutas a mano (fallo de portabilidad Windows/Linux).
  • Instalar un paquete npm para lo que ya hace un nativo.

Puntos clave

  • Los MÓDULOS NATIVOS (fs, path, os, http, crypto…) están integrados en Node (ninguna instalación) y dan acceso al sistema; importados por su nombre.
  • fs (archivos): preferir lo ASÍNCRONO (fs.promises + await, no bloqueante) en servidor; lo síncrono (Sync) bloquea el bucle de eventos (reservado a scripts/configuración).
  • path: manipular las rutas de forma PORTABLE (path.join gestiona el separador correcto / vs \) — nunca concatenar las rutas a mano.
  • os: información del sistema (plataforma, os.cpus para el clustering, memoria). Los nativos son el FUNDAMENTO de las bibliotecas (Express se basa en http).

Desafío 48h — aplique mañana

Escriba el script de inventario del modelo anterior sobre una carpeta real (sus informes, sus exportaciones): registre nombre, tamaño y extensión en asíncrono, con rutas path.join. Destierre toda llamada Sync del script.

Lista de salida de la sección
  • Puedo citar los 3 nativos y su papel en una frase cada uno.
  • Sé escribir un script fs.promises + await sin Sync.
  • He producido un inventario real con rutas portables.
Autoevaluación 1-5: ¿uso lo asíncrono en servidor?¿destierro las rutas concatenadas a mano?

Preguntas frecuentes

Versión asíncrona o síncrona de fs: ¿cuál usar, y cuándo es aceptable lo síncrono?

En servidor, siempre lo asíncrono (fs.promises + await): Node es monohilo, y una llamada síncrona (readFileSync…) bloquea ese hilo durante toda la operación — el servidor no responde entonces a ningún otro cliente. Es exactamente lo que el modelo no bloqueante de Node busca evitar. Lo síncrono solo es aceptable en dos casos: los pequeños scripts puntuales (sin servidor, sin usuarios simultáneos) y la carga de configuración al arranque (una vez, antes de escuchar). Regla de Salim: Sync en la ruta de una petición = fallo de rendimiento.

¿Por qué usar el módulo path en lugar de construir las rutas a mano?

Porque la concatenación manual se rompe en cuanto se cambia de sistema: el separador es / en macOS/Linux pero \ en Windows, y se producen rápido dobles separadores o trozos pegados («archivo no encontrado»). path.join(__dirname, 'data', nom) monta con el separador correcto según el sistema y gestiona los casos límite; path.resolve() produce un absoluto, basename/extname/dirname recortan limpiamente. El código de Salim funciona sin retoques en su Windows y en el Linux del equipo.

Comprueba tu comprensión

Salim lee informes en un servidor usado por todo el equipo. ¿Qué versión de fs?

Recursos adicionales (opcional, para ir más allá)

Examen del nivel 2Preguntas inéditas y más difíciles para validar tus conocimientos