Te traemos la contestación a este inconveniente, al menos eso deseamos. Si tienes inquietudes puedes dejarlo en el apartado de comentarios, que para nosotros será un gusto responderte
Solución:
Para procesar un archivo línea por línea, simplemente necesita desacoplar la lectura del archivo y el código que actúa sobre esa entrada. Puede lograr esto almacenando en búfer su entrada hasta que llegue a una nueva línea. Suponiendo que tenemos un objeto JSON por línea (básicamente, formato B):
var stream = fs.createReadStream(filePath, flags: 'r', encoding: 'utf-8');
var buf = '';
stream.on('data', function(d)
buf += d.toString(); // when data is read, stash it in a string buffer
pump(); // then process the buffer
);
function pump()
var pos;
while ((pos = buf.indexOf('n')) >= 0) // keep going while there's a newline somewhere in the buffer
if (pos == 0) // if there's more than one newline in a row, the buffer will now start with a newline
buf = buf.slice(1); // discard it
continue; // so that the next iteration will start with data
processLine(buf.slice(0,pos)); // hand off the line
buf = buf.slice(pos+1); // and slice the processed data off the buffer
function processLine(line) // here's where we do something with a line
if (line[line.length-1] == 'r') line=line.substr(0,line.length-1); // discard CR (0x0D)
if (line.length > 0) // ignore empty lines
var obj = JSON.parse(line); // parse the JSON
console.log(obj); // do something with the data here!
Cada vez que el flujo de archivos recibe datos del sistema de archivos, se guardan en un búfer y luego pump
se llama.
Si no hay una nueva línea en el búfer, pump
simplemente regresa sin hacer nada. Se agregarán más datos (y potencialmente una nueva línea) al búfer la próxima vez que la secuencia obtenga datos, y luego tendremos un objeto completo.
Si hay una nueva línea, pump
corta el búfer desde el principio hasta la nueva línea y se lo pasa a process
. A continuación, vuelve a comprobar si hay otra nueva línea en el búfer (la while
lazo). De esta forma, podemos procesar todas las líneas que se leyeron en el fragmento actual.
Finalmente, process
se llama una vez por línea de entrada. Si está presente, elimina el carácter de retorno de carro (para evitar problemas con los finales de línea – LF vs CRLF), y luego llama JSON.parse
uno la línea. En este punto, puede hacer lo que necesite con su objeto.
Tenga en cuenta que JSON.parse
es estricto sobre lo que acepta como entrada; debe citar sus identificadores y string valores con comillas dobles. En otras palabras, name:'thing1'
arrojará un error; debes usar "name":"thing1"
.
Debido a que no habrá más de una porción de datos en la memoria a la vez, esto será extremadamente eficiente en términos de memoria. También será extremadamente rápido. Una prueba rápida mostró que procesé 10 000 filas en menos de 15 ms.
Justo cuando estaba pensando que sería divertido escribir un analizador JSON de transmisión, también pensé que tal vez debería hacer una búsqueda rápida para ver si ya hay uno disponible.
Resulta que hay.
- JSONStream “streaming JSON.parse y stringify”
Como lo acabo de encontrar, obviamente no lo he usado, por lo que no puedo comentar sobre su calidad, pero me interesará saber si funciona.
Funciona, considere el siguiente Javascript y _.isString
:
stream.pipe(JSONStream.parse('*'))
.on('data', (d) =>
console.log(typeof d);
console.log("isString: " + _.isString(d))
);
Esto registrará los objetos a medida que entren si la secuencia es un array de objetos Por lo tanto, lo único que se almacena en el búfer es un objeto a la vez.
A partir de octubre de 2014puede hacer algo como lo siguiente (usando JSONStream): https://www.npmjs.org/package/JSONStream
var fs = require('fs'),
JSONStream = require('JSONStream'),
var getStream() = function ()
var jsonData = 'myData.json',
stream = fs.createReadStream(jsonData, encoding: 'utf8' ),
parser = JSONStream.parse('*');
return stream.pipe(parser);
getStream().pipe(MyTransformToDoWhateverProcessingAsNeeded).on('error', function (err)
// handle any errors
);
Para demostrar con un ejemplo de trabajo:
npm install JSONStream event-stream
datos.json:
"greeting": "hello world"
hola.js:
var fs = require('fs'),
JSONStream = require('JSONStream'),
es = require('event-stream');
var getStream = function ()
var jsonData = 'data.json',
stream = fs.createReadStream(jsonData, encoding: 'utf8' ),
parser = JSONStream.parse('*');
return stream.pipe(parser);
;
getStream()
.pipe(es.mapSync(function (data)
console.log(data);
));
$ node hello.js
// hello world