Saltar al contenido

Analizar archivo JSON grande en Nodejs

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

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *