196 votes

node.js : lire un fichier texte dans un tableau. (Chaque ligne est un élément du tableau).

Je voudrais lire un très, très gros fichier dans un tableau JavaScript dans node.js.

Donc, si le fichier est comme ceci :

first line
two 
three
...
...

J'aurais le tableau :

['first line','two','three', ... , ... ] 

La fonction ressemblerait à ceci :

var array = load(filename); 

Par conséquent, l'idée de tout charger sous forme de chaîne et de la diviser ensuite n'est pas acceptable.

0 votes

Cette question a besoin d'être sérieusement modifiée et nettoyée. Il est écrit lire un fichier texte dans un tableau mais quand vous lisez toutes les réponses et les commentaires, cela veut dire en réalité lire un fichier texte une ligne à la fois . Pour cette question, @zswang a la meilleure réponse jusqu'à présent.

0 votes

Oui, il suffit de lire ce fichier et de mettre chaque ligne dans un tableau : stackoverflow.com/a/34033928/1536309

521voto

Finbarr Points 8420

Synchrone :

var fs = require('fs');
var array = fs.readFileSync('file.txt').toString().split("\n");
for(i in array) {
    console.log(array[i]);
}

Asynchrone :

var fs = require('fs');
fs.readFile('file.txt', function(err, data) {
    if(err) throw err;
    var array = data.toString().split("\n");
    for(i in array) {
        console.log(array[i]);
    }
});

12 votes

Merci. Malheureusement, j'ai dû modifier ma question. Je veux dire comment lire un fichier très volumineux. Le lire entièrement dans une chaîne de caractères n'est pas acceptable.

0 votes

Peut-être ne faut-il pas rendre i global et utiliser for(var i in ... à la place ?

1 votes

Juste ce dont j'avais besoin. Simple et rapide.

91voto

mtomis Points 614

Si vous pouvez faire tenir les données finales dans un tableau, ne pourriez-vous pas également les faire tenir dans une chaîne de caractères et les diviser, comme cela a été suggéré ? Dans tous les cas, si vous souhaitez traiter le fichier une ligne à la fois, vous pouvez également essayer quelque chose comme ceci :

var fs = require('fs');

function readLines(input, func) {
  var remaining = '';

  input.on('data', function(data) {
    remaining += data;
    var index = remaining.indexOf('\n');
    while (index > -1) {
      var line = remaining.substring(0, index);
      remaining = remaining.substring(index + 1);
      func(line);
      index = remaining.indexOf('\n');
    }
  });

  input.on('end', function() {
    if (remaining.length > 0) {
      func(remaining);
    }
  });
}

function func(data) {
  console.log('Line: ' + data);
}

var input = fs.createReadStream('lines.txt');
readLines(input, func);

EDIT : (en réponse au commentaire de phopkins ) Je pense (au moins dans les versions plus récentes) que substring ne copie pas les données mais crée un objet spécial SlicedString (d'après un rapide coup d'oeil au code source de la v8). Dans tous les cas, voici une modification qui permet d'éviter le substring mentionné (testé sur un fichier de plusieurs mégaoctets de "All work and no play makes Jack a dull boy") :

function readLines(input, func) {
  var remaining = '';

  input.on('data', function(data) {
    remaining += data;
    var index = remaining.indexOf('\n');
    var last  = 0;
    while (index > -1) {
      var line = remaining.substring(last, index);
      last = index + 1;
      func(line);
      index = remaining.indexOf('\n', last);
    }

    remaining = remaining.substring(last);
  });

  input.on('end', function() {
    if (remaining.length > 0) {
      func(remaining);
    }
  });
}

0 votes

Merci. Pour répondre à votre question : non, la ficelle serait trop grosse.

9 votes

J'ai essayé cela sur des fichiers d'environ 2 Mo et c'était terriblement lent, beaucoup plus lent que la lecture synchrone des fichiers dans une chaîne. Je pense que le problème est la ligne remaining = remaining.substring. Les "données" de Node peuvent vous donner beaucoup à la fois, et faire cette copie pour chaque ligne devient rapidement O(n^2).

1 votes

La réponse de @Finbar est bien meilleure.

79voto

zswang Points 231

Utilisation de Node.js module de lecture en ligne .

var fs = require('fs');
var readline = require('readline');

var filename = process.argv[2];
readline.createInterface({
    input: fs.createReadStream(filename),
    terminal: false
}).on('line', function(line) {
   console.log('Line: ' + line);
});

1 votes

Malheureusement, il y a un problème avec cette solution : Vous n'obtenez pas la dernière ligne si le fichier n'a pas d'extension \n à la fin ! Voir : stackoverflow.com/questions/18450197/

8 votes

Node a corrigé ce problème avec la \n stackoverflow.com/a/32599033/3763850

5voto

Gabriel Llamas Points 5808

Avec un BufferedReader mais la fonction doit être asynchrone :

var load = function (file, cb){
    var lines = [];
    new BufferedReader (file, { encoding: "utf8" })
        .on ("error", function (error){
            cb (error, null);
        })
        .on ("line", function (line){
            lines.push (line);
        })
        .on ("end", function (){
            cb (null, lines);
        })
        .read ();
};

load ("file", function (error, lines){
    if (error) return console.log (error);
    console.log (lines);
});

4voto

oferei Points 401

Il s'agit d'une variante de la réponse donnée ci-dessus par @mtomis.

Il crée un flux de lignes. Elle émet des événements 'data' et 'end', vous permettant de gérer la fin du flux.

var events = require('events');

var LineStream = function (input) {
    var remaining = '';

    input.on('data', function (data) {
        remaining += data;
        var index = remaining.indexOf('\n');
        var last = 0;
        while (index > -1) {
            var line = remaining.substring(last, index);
            last = index + 1;
            this.emit('data', line);
            index = remaining.indexOf('\n', last);
        }
        remaining = remaining.substring(last);
    }.bind(this));

    input.on('end', function() {
        if (remaining.length > 0) {
            this.emit('data', remaining);
        }
        this.emit('end');
    }.bind(this));
}

LineStream.prototype = new events.EventEmitter;

Utilisez-le comme un emballage :

var lineInput = new LineStream(input);

lineInput.on('data', function (line) {
    // handle line
});

lineInput.on('end', function() {
    // wrap it up
});

1 votes

Vous finirez par avoir des événements partagés entre les instances. var EventEmitter = require('events').EventEmitter; var util = require('util'); function GoodEmitter() { EventEmitter.call(this); } util.inherits(GoodEmitter, EventEmitter);

0 votes

De quelles instances parlez-vous exactement ?

1 votes

Essayer de créer var li1 = new LineStream(input1), li2 = new LineStream(input2); puis compter combien de fois 'end' est déclenché pour chacun d'eux.

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