fs.readFile(path, 'utf8', callback) lee un archivo entero y pasa su contenido al callback como string. fs.readFileSync(path, 'utf8') devuelve el string directamente y espera a que termine la lectura, y await readFile(path, 'utf8') de fs/promises hace lo mismo sin bloquear. Si omites 'utf8', obtienes un Buffer de bytes en bruto en lugar de texto.
Primero se imprime readFile called: readFile solo inicia la lectura, y el callback se ejecuta cuando el contenido está listo. Borra 'utf8', y vuelve a ejecutarlo: el callback recibe <Buffer 42 75 79 20 6d 69 6c 6b 0a 43 61 6c 6c 20 41 64 61>, los bytes en bruto del archivo.
readFile vs readFileSync vs fs/promises
Las tres leen el mismo archivo. Se diferencian en cómo obtienes el resultado y en si el resto del programa espera.
La línea síncrona se imprime primero porque no se ejecuta nada más hasta que devuelve. Las otras dos terminan después del código principal, en el orden en que acaben sus lecturas.
readFileSync | readFile (callback) | fs/promises readFile | |
|---|---|---|---|
| Devuelve | El contenido | undefined | Una promesa del contenido |
| Bloquea el programa | Sí | No | No |
| Errores | Se lanzan, usa try/catch | Primer argumento del callback | Promesa rechazada, try/catch con await |
| Úsalo en | Código de arranque y scripts | Código antiguo con callbacks | Código nuevo |
Usa readFileSync para leer una config al arrancar o en un script corto. En un servidor, una lectura síncrona detiene todas las demás peticiones mientras trabaja el disco, así que ahí usa la versión con promesas. La página de fs/promises cubre el resto de esa API.
Manejar un archivo que no existe (ENOENT)
Cuando el archivo no existe, el error tiene code: 'ENOENT' ("error, no entry"). Comprueba err.code para distinguir un archivo que falta de otros fallos, como un problema de permisos.
La primera llamada no encuentra el archivo y usa default settings; la segunda lee dark mode. Volver a lanzar los demás errores mantiene visibles los problemas reales en lugar de usar valores por defecto sin decir nada.
fs.existsSync: por qué es mejor intentar la lectura
fs.existsSync(path) devuelve true o false, y es tentador comprobarlo antes de leer:
if (fs.existsSync('data.txt')) {
const text = fs.readFileSync('data.txt', 'utf8');
}
Son dos pasos donde basta con uno, y el archivo puede borrarse entre ellos, así que la lectura aún puede lanzar un error. Intenta la lectura y maneja ENOENT, como arriba. existsSync está bien cuando solo necesitas saber si algo existe y no lo vas a abrir, por ejemplo para decidir si crear una carpeta.
Leer un archivo JSON
Lee el texto y luego parséalo con JSON.parse. Un archivo con un error de sintaxis lanza un SyntaxError, así que mantenlo dentro del mismo try.
Imprime 3001 y boolean: después de parsear, los valores tienen sus tipos de JSON. require('./config.json') también funciona, pero guarda el resultado en caché, así que un segundo require devuelve el objeto antiguo aunque el archivo haya cambiado.
Leer un archivo línea a línea
Para un archivo que cabe en memoria, léelo entero y sepáralo por el carácter de salto de línea. Filtra el string vacío que deja un salto de línea final.
El split da 4 elementos, el último vacío, así que el bucle imprime tres líneas numeradas. Los archivos escritos en Windows terminan las líneas con \r\n; separa con /\r?\n/ para cubrir los dos casos.
Un log de varios gigas no cabe en memoria. Léelo como stream, para tener una sola línea en memoria cada vez:
const fs = require('fs');
const readline = require('readline');
async function main() {
const rl = readline.createInterface({
input: fs.createReadStream('big.log'),
crlfDelay: Infinity,
});
for await (const line of rl) {
console.log(line);
}
}
main();
Errores comunes
Usar el resultado fuera del callback. const text = fs.readFile(...) es undefined. El contenido solo existe dentro del callback, o después de await.
Olvidar la codificación. Sin 'utf8' obtienes un Buffer, y data.split('\n') lanza data.split is not a function. Pasa la codificación siempre que quieras texto.
Rutas relativas a la carpeta equivocada. 'data.txt' se busca donde se lanzó node. Usa path.join(__dirname, 'data.txt') para un archivo que va junto a tu script.
Preguntas frecuentes
¿Por qué fs.readFile devuelve undefined?
fs.readFile no devuelve el contenido. Inicia la lectura y llama a tu callback más tarde con (err, data). Usa los datos dentro del callback, llama a readFileSync o haz await de la versión con promesas.
¿Dónde busca Node una ruta relativa como 'data.txt'?
En el directorio de trabajo actual, la carpeta desde la que ejecutaste node, no en la carpeta del script. Para leer un archivo que está junto al script, construye la ruta con path.join(__dirname, 'data.txt').
¿Puede fs.readFile leer un archivo desde una URL?
No, solo lee del sistema de archivos. Para obtener un archivo por HTTP, usa fetch y luego await res.text().
¿Qué tamaño de archivo aguanta readFile?
Carga el archivo entero en memoria, así que va bien para configs, plantillas y archivos de datos pequeños. Para archivos de cientos de megas, léelos por partes con fs.createReadStream.