148 votes

Analyser des fichiers journaux volumineux en Node.js - lire ligne par ligne

Je dois analyser des fichiers journaux volumineux (5 à 10 Go) en Javascript/Node.js (j'utilise Cube).

La ligne de conduite ressemble à quelque chose comme :

10:00:43.343423 I'm a friendly log message. There are 5 cats, and 7 dogs. We are in state "SUCCESS".

Nous devons lire chaque ligne, faire un peu d'analyse syntaxique (par exemple, enlever les caractères 5 , 7 et SUCCESS ), puis de pomper ces données dans Cube ( https://github.com/square/cube ) en utilisant leur client JS.

Tout d'abord, quelle est la manière canonique dans Node de lire un fichier, ligne par ligne ?

Cette question semble être assez courante sur Internet :

Beaucoup de réponses semblent pointer vers un tas de modules tiers :

Cependant, cela semble être une tâche assez basique - il y a sûrement un moyen simple dans la stdlib pour lire un fichier texte, ligne par ligne ?

Ensuite, je dois traiter chaque ligne (par exemple, convertir l'horodatage en un objet Date, et extraire les champs utiles).

Quelle est la meilleure façon de le faire, en maximisant le débit ? Existe-t-il un moyen de ne pas bloquer la lecture de chaque ligne ou l'envoi au Cube ?

Troisièmement, je suppose que l'utilisation des séparations de chaînes de caractères et de l'équivalent JS de contains (IndexOf != -1 ?) sera beaucoup plus rapide que les regex ? Quelqu'un a-t-il une grande expérience de l'analyse de quantités massives de données textuelles dans Node.js ?

A la vôtre, Victor

1voto

Raza Farooq Points 57
import * as csv from 'fast-csv';
import * as fs from 'fs';
interface Row {
  [s: string]: string;
}
type RowCallBack = (data: Row, index: number) => object;
export class CSVReader {
  protected file: string;
  protected csvOptions = {
    delimiter: ',',
    headers: true,
    ignoreEmpty: true,
    trim: true
  };
  constructor(file: string, csvOptions = {}) {
    if (!fs.existsSync(file)) {
      throw new Error(`File ${file} not found.`);
    }
    this.file = file;
    this.csvOptions = Object.assign({}, this.csvOptions, csvOptions);
  }
  public read(callback: RowCallBack): Promise < Array < object >> {
    return new Promise < Array < object >> (resolve => {
      const readStream = fs.createReadStream(this.file);
      const results: Array < any > = [];
      let index = 0;
      const csvStream = csv.parse(this.csvOptions).on('data', async (data: Row) => {
        index++;
        results.push(await callback(data, index));
      }).on('error', (err: Error) => {
        console.error(err.message);
        throw err;
      }).on('end', () => {
        resolve(results);
      });
      readStream.pipe(csvStream);
    });
  }
}

import { CSVReader } from '../src/helpers/CSVReader';
(async () => {
  const reader = new CSVReader('./database/migrations/csv/users.csv');
  const users = await reader.read(async data => {
    return {
      username: data.username,
      name: data.name,
      email: data.email,
      cellPhone: data.cell_phone,
      homePhone: data.home_phone,
      roleId: data.role_id,
      description: data.description,
      state: data.state,
    };
  });
  console.log(users);
})();

-1voto

Eyal Zoref Points 15

J'ai réalisé un module node pour lire de manière asynchrone de gros fichiers texte ou JSON. Testé sur de gros fichiers.

var fs = require('fs')
, util = require('util')
, stream = require('stream')
, es = require('event-stream');

module.exports = FileReader;

function FileReader(){

}

FileReader.prototype.read = function(pathToFile, callback){
    var returnTxt = '';
    var s = fs.createReadStream(pathToFile)
    .pipe(es.split())
    .pipe(es.mapSync(function(line){

        // pause the readstream
        s.pause();

        //console.log('reading line: '+line);
        returnTxt += line;        

        // resume the readstream, possibly from a callback
        s.resume();
    })
    .on('error', function(){
        console.log('Error while reading file.');
    })
    .on('end', function(){
        console.log('Read entire file.');
        callback(returnTxt);
    })
);
};

FileReader.prototype.readJSON = function(pathToFile, callback){
    try{
        this.read(pathToFile, function(txt){callback(JSON.parse(txt));});
    }
    catch(err){
        throw new Error('json file is not valid! '+err.stack);
    }
};

Il suffit d'enregistrer le fichier sous le nom de file-reader.js, et de l'utiliser comme suit :

var FileReader = require('./file-reader');
var fileReader = new FileReader();
fileReader.readJSON(__dirname + '/largeFile.json', function(jsonObj){/*callback logic here*/});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X