Quiz: Dominio de IO en NodeJS
Pon a prueba tus conocimientos sobre archivos, flujos y buffers
¿Listo para sumergirte en el mundo del IO de NodeJS? 🌊
Este cuestionario pondrá a prueba tu comprensión de las operaciones de IO de Node, desde las tareas básicas del sistema de archivos hasta los conceptos avanzados de streaming. Cubriremos buffers, codificaciones y buenas prácticas para manejar datos de forma eficiente.
¡Veamos qué tan bien conoces tus streams frente a tus buffers! 🚀
¿Qué hace este código?
const buf = Buffer.alloc(5);console.log(buf);Buffer.alloc(size) crea un nuevo Buffer del tamaño especificado relleno de ceros.
La salida será: <Buffer 00 00 00 00 00>
Si deseas crear un Buffer con datos aleatorios, usa Buffer.allocUnsafe(5).
¿Qué imprimirá esto?
const buf = Buffer.from([65]);console.log(buf.toString());Los números en el arreglo representan códigos ASCII:
- 65: ‘A’
toString() convierte estos bytes a su representación en cadena usando codificación UTF-8 por defecto.
¿Cuál es el orden de salida?
import fs from 'fs';fs.readFile('test.txt', 'utf8', (err, data) => { console.log(data);});console.log('Done');Como readFile es asíncrono, el código sigue ejecutándose mientras se lee el archivo.
Por lo tanto, “Done” se imprimirá antes del contenido del archivo.
Para esperar a que el archivo se lea primero, podrías usar la versión basada en Promesas:
import { promises as fs } from 'fs';
async function read() { const data = await fs.readFile('test.txt', 'utf8'); console.log(data); console.log('Done');}¿Qué devuelve fs.readFileSync() por defecto?
import fs from 'fs';const content = fs.readFileSync('test.txt');fs.readFileSync() devuelve un Buffer por defecto cuando no se especifica una codificación. Si quieres una cadena, debes:
- Especificar una codificación:
fs.readFileSync('test.txt', 'utf8') - Convertir el Buffer:
content.toString()
Aprende más sobre fs.readFileSync en la documentación de Node.js
¿Qué conjunto de eventos se usa comúnmente con los streams legibles?
Los streams legibles emiten varios eventos importantes:
- ‘data’: Cuando hay datos disponibles para leer
- ‘end’: Cuando no hay más datos que leer
- ‘error’: Cuando ocurre un error
- ‘close’: Cuando el stream y el recurso subyacente se han cerrado
const readable = fs.createReadStream('file.txt');readable.on('data', chunk => console.log(chunk));readable.on('end', () => console.log('Done!'));¿Qué hace este código?
import fs from 'fs';const readable = fs.createReadStream('source.txt');const writable = fs.createWriteStream('dest.txt');readable.pipe(writable);pipe() conecta un stream legible a un stream escribible, gestionando automáticamente la presión inversa y copiando los datos en fragmentos sin cargar todo el archivo en memoria.
Esto es eficiente en memoria para archivos grandes en comparación con fs.readFile() seguido de fs.writeFile().
¿Qué hace la opción recursive?
import fs from 'fs';fs.mkdirSync('./a/b/c', { recursive: true });La opción recursive: true crea los directorios padre si no existen.
Sin esta opción, intentar crear ’./a/b/c’ lanzaría un error si ’./a’ o ’./a/b’ no existen.
Es similar al comando de shell mkdir -p.
¿Qué mostrará esto?
import { Transform } from 'stream';const upperCase = new Transform({ transform(chunk, encoding, callback) { callback(null, chunk.toString().toUpperCase()); }});process.stdin .pipe(upperCase) .pipe(process.stdout);// Input: "hello world"Los flujos de transformación modifican los datos mientras los atraviesan. Aquí, cada fragmento se:
- Convierte a una cadena
- Transforma a mayúsculas
- Se envía a stdout
Esto crea una canalización que convierte toda la entrada a mayúsculas.
¿Cuántas veces se garantiza que fs.watch() se dispare cuando se modifica un archivo?
import fs from 'fs';fs.watch('test.txt', (eventType, filename) => { console.log(`${filename} was changed`);});// Then modify test.txt oncefs.watch() no garantiza dispararse exactamente una vez por cada cambio lógico de archivo. A menudo se dispara varias veces porque muchos editores de texto:
- Guardan en un archivo temporal
- Lo renombran al archivo objetivo
Para una observación más fiable, considera usar:
- El paquete
chokidar - Aplicar debounce al callback
- Usar
fs.watchFile()(aunque es menos eficiente)
¿Cuál es la salida?
const buf1 = Buffer.from('Hello');const buf2 = Buffer.from('Hello');console.log(buf1 === buf2);Los buffers se comparan por referencia, no por valor. Aunque contengan los mismos datos, son objetos diferentes.
Para comparar el contenido de los buffers, use:
buf1.equals(buf2) // true// orBuffer.compare(buf1, buf2) === 0 // true¿Cuál es el propósito principal del backpressure en streams?
El backpressure es un mecanismo que previene el desbordamiento de memoria pausando la lectura cuando el extremo de escritura no puede seguir el ritmo.
Ejemplo de backpressure manual:
readable.on('data', (chunk) => { const canContinue = writable.write(chunk); if (!canContinue) { readable.pause(); writable.once('drain', () => readable.resume()); }});pipe() maneja esto automáticamente!
¿Qué hace este código?
import fs from 'fs';fs.symlinkSync('target.txt', 'link.txt');symlinkSync crea un enlace simbólico (como un acceso directo) al archivo objetivo.
Diferencias clave con los enlaces duros:
- Puede enlazar a directorios
- Puede abarcar sistemas de archivos
- Se rompe si el objetivo se elimina
Para crear un enlace duro en su lugar:
fs.linkSync('target.txt', 'hardlink.txt');¿En qué modos pueden operar los streams de Node.js?
Los streams pueden operar en:
- Modo binario (por defecto): para buffers y cadenas
- Modo objeto: para cualquier valor de JavaScript
Ejemplo de modo objeto:
import { Transform } from 'stream';const objectStream = new Transform({ objectMode: true, transform(chunk, encoding, callback) { callback(null, { value: chunk }); }});¿Qué tipo es el parámetro fd en esta devolución de llamada?
import fs from 'fs';fs.open('test.txt', 'r', (err, fd) => { console.log(typeof fd);});Los descriptores de archivo son números que identifican de forma única los archivos abiertos en el sistema operativo.
Los tres primeros descriptores están reservados:
- 0: stdin
- 1: stdout
- 2: stderr
Recuerda siempre cerrar los descriptores de archivo:
fs.close(fd, (err) => { if (err) throw err;});¿Cuántos bytes ocupará esta cadena en UTF-8?
const str = "Hello 🌍";const buf = Buffer.from(str);console.log(buf.length);En UTF-8:
- Los caracteres ASCII (como ‘Hello ’) ocupan 1 byte cada uno
- El emoji de la tierra 🌍 ocupa 4 bytes
Entonces: 5 (Hello) + 1 (espacio) + 4 (🌍) = 10 bytes
Para ver los bytes:
console.log(buf); // <Buffer 48 65 6c 6c 6f 20 f0 9f 8c 8d>¡Espero que hayas disfrutado poniendo a prueba tus conocimientos de NodeJS IO! ¿Quieres más? Consulta mi Colección de quizzes para nuevos desafíos.