web-dev-qa-db-fra.com

Lire les lignes de façon synchronisée à partir du fichier dans Node.js

J'ai besoin d'analyser un fichier ligne par ligne dans le format suivant avec Node.js:

13
13
0 5
4 3
0 1
9 12
6 4
5 4
0 2
11 12
9 10
0 6
7 8
9 11
5 3

Cela représente un graphique. Les deux premières lignes représentent le nombre d'arêtes et de sommets, suivies des arêtes.

Je peux accomplir la tâche avec quelque chose comme:

var fs = require('fs');
var readline = require('readline');
var read_stream = fs.createReadStream(filename);
var rl = readline.createInterface({
    input: read_stream
});
var c = 0;
var vertexes_number;
var edges_number;
var edges = [];
rl.on('line', function(line){
    if (c==0) {
        vertexes_number = parseInt(line);
    } else if (c==1) {
        edges_number = parseInt(line);
    } else {
        edges.Push(line.split(' '));
    }
    c++;
})
.on('end', function(){
    rl.close();
})

Je comprends que ce genre de choses puisse ne pas être ce pour quoi Node.js a été pensé, mais la variable if en cascade dans le rappel line ne me semble pas vraiment élégante/lisible. 

Existe-t-il un moyen de lire de manière synchrone des lignes à partir d'un flux, comme dans tous les autres langages de programmation?

Je suis ouvert à utiliser des plugins s'il n'y a pas de solution intégrée.

[MODIFIER]

Désolé, j'aurais dû préciser que je voudrais éviter de charger tout le fichier en mémoire auparavant

19
Andrea Casaccia

Ce projet sur github.com fait exactement ce dont j'avais besoin:

https://github.com/nacholibre/node-readlines

var readlines = require('n-readlines');
var liner = new readlines(filename);

var vertexes_number = parseInt(liner.next().toString('ascii'));
var edges_number = parseInt(liner.next().toString('ascii'));
var edges = [];
var next;
while (next = liner.next()) {
    edges.Push(next.toString('ascii').split(' '));
}
10
Andrea Casaccia

Ma partie de code habituelle pour de telles tâches simples:

var lines = require('fs').readFileSync(filename, 'utf-8')
    .split('\n')
    .filter(Boolean);

lines est un tableau de chaînes sans celles qui sont vides.

26
Alexey Ten

Pourquoi ne pas les lire tous dans un tableau, puis extraire les deux premiers éléments avec épissure. Je suppose que votre exemple est très simplifié ou vous liriez tout le fichier en mémoire et le scinderiez. Si votre cas réel stocke plusieurs graphiques et que vous voulez faire quelque chose lorsque chacun d'eux est chargé, par exemple, vous pouvez mettre un test dans votre événement de ligne.

var fs = require('fs');
var readline = require('readline');
var read_stream = fs.createReadStream(filename);
var rl = readline.createInterface({
    input: read_stream
});

var buffer = [];

rl.on('line', function(line){
    buffer.Push(line.split(' '));
    //Not sure what your actual requirement is but if you want to do 
    //something  like display a graph once one has loaded
    //obviously need to be able to determine when one has completed loading
    if ( buffer.length == GRAPHLENGTH) {  //or some other test
        displayGraph(buffer);
        buffer = [];
    }    
})
.on('close', function(){
    //or do it here if there is only one graph
    //displayGraph(buffer);
    rl.close();
})

function displayGraph(buffer){
    var vertexes_number = parseInt(buffer.splice(0,1));
    var edges_number = parseInt(buffer.splice(0,1));
    var edges = buffer;

    //doYourThing(vertexes_number, edges_number, edges);
}
1
Dave Pile

Personnellement, j'aime bien utiliser event-stream pour gérer les flux. Ce n'est pas nécessaire ici mais je l'ai utilisé pour l'exemple de code. C’est simple, j’analyse int et je place tout dans edges, puis lorsque la lecture du fichier est terminée, je prends le premier élément qui est vertexes_number, le nouveau premier élément est edges_number

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

var filename = 'parse-file.txt';

var vertexes_number, edges_number;
var edges = [];

fs.createReadStream(filename)
    .pipe(es.split()) // split by lines
    .pipe(es.map(function (line, next) {
        // split and convert all to numbers
        edges.Push(line.split(' ').map((n) => +n));

        next(null, line);
    })).pipe(es.wait(function (err, body) {
        // the first element is an array containing vertexes_number
        vertexes_number = edges.shift().pop();

        // the following element is an array containing edges_number
        edges_number = edges.shift().pop();

        console.log('done');
        console.log('vertexes_number: ' + vertexes_number);
        console.log('edges_number: ' + edges_number);
        console.log('edges: ' + JSON.stringify(edges, null, 3));
    }));
0
Shanoor