Leer un archivo línea por línea en Node.js

En Ciencias de la Computación, un archivo es un recurso utilizado para registrar datos de forma discreta en el dispositivo de almacenamiento de una computadora. Node.js no anula esto de ninguna manera y funciona con...

Introducción

En Ciencias de la Computación, un archivo es un recurso utilizado para registrar datos discretamente en el dispositivo de almacenamiento de una computadora. Node.js no anula esto de ninguna manera y funciona con cualquier cosa que se considere un archivo en su sistema de archivos.

La lectura de archivos y recursos tiene muchos usos:

  • Estadísticas, análisis e informes
  • Aprendizaje automático
  • Manejo de grandes archivos de texto o registros

A veces, estos archivos pueden ser absurdamente grandes, con gigabytes o terabytes almacenados, y leerlos en su totalidad es ineficiente.

Ser capaz de leer un archivo línea por línea nos brinda la posibilidad de buscar solo la información relevante y detener la búsqueda una vez que hayamos encontrado lo que estamos buscando. También nos permite dividir los datos en partes lógicas, como si el archivo tuviera formato CSV.

Readline (desde v0.12 en adelante)

Node.js tiene el módulo nativo para leer archivos que nos permite leer línea por línea. Se agregó en 2015 y está diseñado para leer de cualquier flujo “Legible” una línea a la vez.

Este hecho lo convierte en una opción versátil, adecuada no solo para archivos, sino también para entradas de línea de comandos como process.stdin. La documentación sobre el módulo readline se puede encontrar aquí.

Como readline es un módulo nativo. No tiene que usar npm en ningún otro administrador de paquetes para agregarlo, solo require:

1
const readline = require('readline');

¡y estás listo para irte!

Como el método readline se debe proporcionar con un flujo, primero debemos crearlo usando otro módulo nativo: fs:

1
const fs = require('fs');

El siguiente paso es crear el objeto que leerá de la secuencia usando la función createInterface():

1
2
3
4
5
const readInterface = readline.createInterface({
    input: fs.createReadStream('/path/to/file'),
    output: process.stdout,
    console: false
});

Asegúrese de sustituir /ruta/al/archivo con la ruta real a un archivo en su sistema de archivos.

Una vez que se realiza la preparación, se puede leer un archivo línea por línea e imprimir su contenido en la consola:

1
2
3
readInterface.on('line', function(line) {
    console.log(line);
});

Aquí esencialmente estamos diciendo que siempre que ocurra el evento line en readInterface, debe llamar a nuestra función y pasarle el contenido leído de la transmisión. En nuestro caso, no queremos complicar demasiado las cosas y simplemente imprimirlo en la consola.

Lector de líneas

Después de una explicación detallada de cómo puede leer un archivo línea por línea usando el módulo nativo de Node.js, echemos un vistazo a una versión más corta usando el código abierto [lector de línea] (https: //www.npmjs.com/package/line-reader) módulo de npm.

Como es un módulo no nativo, debemos asegurarnos de haber inicializado el proyecto npm correctamente con npm init y luego instalarlo:

1
$ npm install --save line-reader

Esto instalará la dependencia y la agregará al archivo package.json.

Una vez hecho esto, la lectura de un archivo línea por línea es similar al ejemplo anterior solo que sin crear una interfaz de lectura en el medio:

1
2
3
4
5
const lineReader = require('line-reader');

lineReader.eachLine('/path/to/file', function(line) {
    console.log(line);
});

Una característica bastante útil aquí es dejar de leer cuando alguna condición se vuelve verdadera. Esto se logra simplemente devolviendo falso desde la función de devolución de llamada.

Por ejemplo, podríamos leer un archivo línea por línea hasta encontrar una línea que contenga la palabra "STOP":

1
2
3
4
5
6
lineReader.eachLine('path/to/file', function(line) {
    console.log(line);
    if (line.includes('STOP') {
        return false; // stop reading
    }
});

Hay un enfoque ligeramente diferente, que utiliza dos devoluciones de llamada anidadas y una sintaxis que puede parecer más natural para los desarrolladores de Java:

1
2
3
4
5
6
7
lineReader.open('/path/to/file', function(reader) {
    if (reader.hasNextLine()) {
        reader.nextLine(function(line) {
            console.log(line);
        });
    }
});

Aquí, estamos usando la función open(), que no nos proporciona las líneas de un archivo instantáneamente, sino que nos proporciona un lector. Tiene su propio conjunto de funciones como hasNextLine() y nextLine() que nos permiten tener un poco más de control sobre el proceso de lectura de un archivo línea por línea en Node.js.

N-líneas de lectura {#nlíneas de lectura}

El módulo npm n-líneas de lectura proporciona una sintaxis diferente:

Vamos a instalarlo:

1
$ npm install --save n-readlines

Y lo requiere:

1
const lineByLine = require('n-readlines');

Para poder leer desde un archivo, debemos crear un nuevo objeto, proporcionando una ruta a nuestro archivo como argumento:

1
const liner = new lineByLine('/path/to/file');

Obtener las líneas del archivo se hace llamando a la función siguiente:

1
2
3
4
5
let line;
 
while (line = liner.next()) {
    console.log(line);
}

Una función interesante del módulo n-readlines es reset(). Restablece el puntero e inicia el proceso de lectura desde el principio del archivo.

Nota: Funciona solo si no se llega al final.

Errores comunes

Un error común al leer un archivo línea por línea en Node.js es leer todo el archivo en la memoria y luego dividir su contenido por saltos de línea.

Aquí hay un ejemplo incorrecto que podría sobrecargar su sistema si le proporciona un archivo lo suficientemente grande:

1
2
3
require('fs').readFileSync('/path/to/file', 'utf-8').split(/\r?\n/).forEach(function(line) {
    console.log(line);
});

A primera vista, parece que el resultado es el mismo para este enfoque que para los anteriores y, de hecho, funciona bien para archivos pequeños. Pero adelante, intenta trabajar con uno grande. Definitivamente no es algo que quieras ver en tu sistema de producción.

Conclusión

Hay múltiples formas de leer un archivo línea por línea en Node.js, y la selección del enfoque apropiado es completamente una decisión del programador.

Debe pensar en el tamaño de los archivos que planea procesar, los requisitos de rendimiento, el estilo del código y los módulos que ya están en el proyecto. Asegúrese de probar en algunos casos de esquina como archivos grandes, vacíos o inexistentes, y estará listo para continuar con cualquiera de los ejemplos proporcionados.