Estoy tratando de leer un archivo grande una línea a la vez. Encontré una pregunta sobre Quora que trataba el tema, pero me faltan algunas conexiones para que todo encaje.
var Lazy=require("lazy");
new Lazy(process.stdin)
.lines
.forEach(
function(line) {
console.log(line.toString());
}
);
process.stdin.resume();
Lo que me gustaría averiguar es cómo podría leer una línea a la vez desde un archivo en lugar de STDIN como en este ejemplo.
Lo intenté:
fs.open('./VeryBigFile.csv', 'r', '0666', Process);
function Process(err, fd) {
if (err) throw err;
// DO lazy read
}
Pero no está funcionando. Sé que en un apuro podría recurrir a usar algo como PHP, pero me gustaría resolver esto.
No creo que la otra respuesta funcione ya que el archivo es mucho más grande que el servidor en el que lo estoy ejecutando tiene memoria.
fs.readSync()
. Puede leer octetos binarios en un búfer, pero no hay una manera fácil de tratar con caracteres UTF-8 o UTF-16 parciales sin inspeccionar el búfer antes de traducirlo a cadenas de JavaScript y buscar EOL. ElBuffer()
tipo no tiene un conjunto de funciones tan rico para operar en sus instancias como las cadenas nativas, pero las cadenas nativas no pueden contener datos binarios. Me parece que la falta de una forma integrada de leer líneas de texto de archivos arbitrarios es una brecha real en node.js.if (line.length==1 && line[0] == 48) special(line);
node
los documentos API de github.com/nodejs/node/pull/4609Respuestas:
Desde Node.js v0.12 y como de Node.js v4.0.0, hay una estable readline módulo de núcleo. Aquí está la forma más fácil de leer líneas de un archivo, sin ningún módulo externo:
O alternativamente:
La última línea se lee correctamente (a partir del Nodo v0.12 o posterior), incluso si no hay una final
\n
.ACTUALIZACIÓN : este ejemplo se ha agregado a la documentación oficial de la API de Node .
fuente
rl.on('close', cb)
Para una operación tan simple, no debería haber ninguna dependencia en módulos de terceros. Con calma.
fuente
line
eventos se\n
producen solo después de golpear , es decir, se pierden todas las alternativas (ver unicode.org/reports/tr18/#Line_Boundaries ). # 2, los datos después del último\n
se ignoran silenciosamente (consulte stackoverflow.com/questions/18450197/… ). Llamaría a esta solución peligrosa porque funciona para el 99% de todos los archivos y para el 99% de los datos, pero falla silenciosamente para el resto. cada vez que lo hacefs.writeFileSync( path, lines.join('\n'))
, ha escrito un archivo que solo será leído parcialmente por la solución anterior.readline
paquete se comporta de maneras realmente extrañas para un programador experimentado de Unix / Linux.rd.on("close", ..);
puede usarse como una devolución de llamada (ocurre cuando se leen todas las líneas)No tiene que
open
usar el archivo, sino que debe crear unReadStream
.fs.createReadStream
Luego pasa esa corriente a
Lazy
fuente
new lazy(fs.createReadStream('...')).lines.forEach(function(l) { /* ... */ }).join(function() { /* Done */ })
new lazy(...).lines.forEach(...).on('end', function() {...})
.on('end'...
después.forEach(...)
, cuando de hecho todo se comportó como se esperaba cuando limité el evento primero .hay un módulo muy bueno para leer un archivo línea por línea, se llama lector de línea
con él simplemente escribes:
incluso puede iterar el archivo con una interfaz "estilo java", si necesita más control:
fuente
process/stdin
). Al menos, si puede, ciertamente no es obvio al leer el código y al intentarlo.readline
módulo central .function(reader)
yfunction(line)
debería ser:function(err,reader)
yfunction(err,line)
.line-reader
lee el archivo de forma asincrónica. La alternativa sincrónica esline-reader-sync
fuente
Actualización en 2019
Un ejemplo impresionante ya está publicado en la documentación oficial de Nodejs. aquí
Esto requiere que el último Nodejs esté instalado en su máquina. > 11.4
fuente
await
s entre lacreateInterface()
llamada y el inicio delfor await
bucle, perderá misteriosamente las líneas desde el inicio del archivo.createInterface()
comienza inmediatamente a emitir líneas detrás de escena, y el iterador asíncrono creado implícitamente conconst line of rl
no puede comenzar a escuchar esas líneas hasta que se crea.Viejo tema, pero esto funciona:
Simple. No es necesario un módulo externo.
fuente
readline is not defined
ofs is not defined
, agreguevar readline = require('readline');
yvar fs = require('fs');
para que esto funcione. De lo contrario dulce, dulce código. Gracias.Siempre puede rodar su propio lector de línea. Todavía no he comparado este fragmento, pero divide correctamente la secuencia entrante de fragmentos en líneas sin el '\ n' final
Se me ocurrió esto cuando trabajé en un script de análisis de registro rápido que necesitaba acumular datos durante el análisis de registro y sentí que sería bueno intentar hacerlo usando js y node en lugar de usar perl o bash.
De todos modos, creo que los scripts pequeños de nodejs deberían ser independientes y no depender de módulos de terceros, por lo que después de leer todas las respuestas a esta pregunta, cada uno con varios módulos para manejar el análisis de líneas, una solución de 13 nodejs nativos de SLOC podría ser de interés.
fuente
stdin
... a menos que me falte algo.ReadStream
confs.createReadStream('./myBigFile.csv')
y usarlo en lugar destdin
readline
módulo central .Con el módulo portador :
fuente
var inStream = fs.createReadStream('input.txt', {flags:'r'});
pero su sintaxis es más limpia que el método documentado de usar .on ():carrier.carry(inStream).on('line', function(line) { ...
\r\n
y\n
termina las líneas. Si alguna vez necesita lidiar con archivos de prueba de estilo MacOS anteriores a OS X, se utilizan\r
y el operador no maneja esto. Sorprendentemente, todavía hay tales archivos flotando en la naturaleza. Es posible que también deba manejar explícitamente la lista de materiales Unicode (marca de orden de bytes), esto se usa al comienzo de los archivos de texto en la esfera de influencia de MS Windows.readline
módulo central .Terminé con una pérdida masiva de memoria masiva usando Lazy para leer línea por línea al intentar procesar esas líneas y escribirlas en otra secuencia debido a la forma en que funciona el drenaje / pausa / reanudación en el nodo (ver: http: // elegantcode .com / 2011/04/06 / tomando-baby-steps-with-node-js-pumping-data-between-streams ((me encanta este chico por cierto)). No he mirado lo suficientemente de cerca a Lazy para entender exactamente por qué, pero no pude detener mi flujo de lectura para permitir un drenaje sin que Lazy salga.
Escribí el código para procesar archivos csv masivos en documentos xml, puedes ver el código aquí: https://github.com/j03m/node-csv2xml
Si ejecuta las revisiones anteriores con la línea Lazy, se filtra. La última revisión no pierde nada y probablemente pueda usarla como base para un lector / procesador. Aunque tengo algunas cosas personalizadas allí.
Editar: Supongo que también debería tener en cuenta que mi código con Lazy funcionó bien hasta que me encontré escribiendo fragmentos xml lo suficientemente grandes que drenan / pausan / reanudan por necesidad. Para trozos más pequeños estaba bien.
fuente
readline
módulo central .Editar:
Utiliza una secuencia de transformación .
Con un BufferedReader puedes leer líneas.
fuente
readline
módulo central .Desde que publiqué mi respuesta original, descubrí que dividir es un módulo de nodo muy fácil de usar para leer líneas en un archivo; Que también acepta parámetros opcionales.
No he probado en archivos muy grandes. Háganos saber si lo hace.
fuente
Estaba frustrado por la falta de una solución integral para esto, así que armé mi propio intento ( git / npm ). Lista de características copiadas y pegadas:
¿NIH? Tú decides :-)
fuente
fuente
data
llamadastream.on("data")
podría comenzar o terminar con solo una parte de un carácter UTF-8 multibyte como elა
que estáU+10D0
formado por los tres bytese1
83
90
readline
módulo central .Quería abordar este mismo problema, básicamente lo que en Perl sería:
Mi caso de uso era solo una secuencia de comandos independiente, no un servidor, por lo que sincronizar estaba bien. Estos fueron mis criterios:
Este es un proyecto para mí para tener una idea del código de tipo scripting de bajo nivel en node.js y decidir qué tan viable es como reemplazo de otros lenguajes de scripting como Perl.
Después de un sorprendente esfuerzo y un par de falsos comienzos, este es el código que se me ocurrió. Es bastante rápido pero menos trivial de lo que esperaba: (bifurca en GitHub)
Probablemente podría limpiarse más, fue el resultado de prueba y error.
fuente
En la mayoría de los casos, esto debería ser suficiente:
fuente
Lector de línea basado en generador: https://github.com/neurosnap/gen-readlines
fuente
Si desea leer un archivo línea por línea y escribir esto en otro:
fuente
Tuve el mismo problema y se me ocurrió que la solución anterior parece similar a los demás, pero es aSync y puede leer archivos grandes muy rápidamente
Espera que esto ayude
fuente
Tengo un pequeño módulo que hace esto bien y es utilizado por muchos otros proyectos npm readline Nota que en el nodo v10 hay un módulo de readline nativo, así que volví a publicar mi módulo como linebyline https://www.npmjs.com/package/ linea por linea
Si no desea utilizar el módulo, la función es muy simple:
fuente
Otra solución es ejecutar la lógica a través del ejecutor secuencial nsynjs . Lee el archivo línea por línea usando el módulo de línea de lectura del nodo, y no usa promesas o recursividad, por lo tanto, no fallará en archivos grandes. Así es como se verá el código:
El código anterior se basa en este examen: https://github.com/amaksr/nsynjs/blob/master/examples/node-readline/index.js
fuente
Dos preguntas que debemos hacernos al hacer tales operaciones son:
Soluciones como
require('fs').readFileSync()
carga todo el archivo en la memoria. Eso significa que la cantidad de memoria requerida para realizar operaciones será casi equivalente al tamaño del archivo. Deberíamos evitarlos para algo más grande que50mbs
Podemos rastrear fácilmente la cantidad de memoria utilizada por una función colocando estas líneas de código después de la invocación de la función:
En este momento la mejor manera de leer las líneas particulares de un archivo de gran tamaño está utilizando el nodo de readline . La documentación tiene ejemplos asombrosos .
Aunque no necesitamos ningún módulo de terceros para hacerlo. Pero, si está escribiendo un código de empresa, debe manejar muchos casos extremos. Tuve que escribir un módulo muy liviano llamado Apick File Storage para manejar todos esos casos .
Módulo Apick File Storage: https://www.npmjs.com/package/apickfs Documentación: https://github.com/apickjs/apickFS#readme
Archivo de ejemplo: https://1drv.ms/t/s!AtkMCsWInsSZiGptXYAFjalXOpUx
Ejemplo: instalar módulo
Este método se probó con éxito con archivos densos de hasta 4 GB.
big.text es un archivo de texto denso con 163.845 líneas y es de 124 Mb. La secuencia de comandos para leer 10 líneas diferentes de este archivo utiliza aproximadamente solo 4,63 MB de memoria solamente. Y analiza JSON válido para objetos o matrices de forma gratuita. 🥳 Impresionante !!
Podemos leer una sola línea del archivo o cientos de líneas del archivo con muy poco consumo de memoria.
fuente
yo uso esto:
use esta función en una secuencia y escuche los eventos de línea que se emitirán.
gramo-
fuente
Si bien probablemente debería usar el
readline
módulo como sugiere la respuesta principal,readline
parece estar orientado hacia las interfaces de línea de comando en lugar de la lectura de línea. También es un poco más opaco con respecto al almacenamiento en búfer. (Cualquiera que necesite un lector orientado a la línea de transmisión probablemente querrá ajustar los tamaños del búfer). El módulo de línea de lectura es ~ 1000 líneas, mientras que esto, con estadísticas y pruebas, es 34.Aquí hay una versión aún más corta, sin las estadísticas, en 19 líneas:
fuente
fuente
Envuelvo toda la lógica del procesamiento diario de líneas como un módulo npm: line-kit https://www.npmjs.com/package/line-kit
fuente
Utilizo el siguiente código de las líneas de lectura después de verificar que no es un directorio y que no está incluido en la lista de archivos, no es necesario verificarlo.
fuente
He revisado todas las respuestas anteriores, todas ellas usan una biblioteca de terceros para resolverlo. Tiene una solución simple en la API de Node. p.ej
fuente