web-dev-qa-db-fra.com

node.js: lit 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 ça:

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 en tant que chaîne, puis de la scinder, n'est pas acceptable.

129
chacko

Si vous pouvez ajuster les données finales dans un tableau, ne pourrez-vous pas aussi l’ajuster dans une chaîne et le scinder, comme cela a été suggéré? Dans tous les cas, si vous souhaitez traiter le fichier une ligne à la fois une fois, vous pouvez aussi 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 (du moins dans les versions les plus récentes) que string ne copie pas de données, mais crée un objet spécial SlicedString (à partir d'un coup d'œil rapide sur le code source v8). En tout cas voici une modification qui évite la sous-chaîne mentionnée (testé sur un fichier de plusieurs mégaoctets de "Tout le travail et aucun jeu ne font de Jack un garçon ennuyeux"):

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);
    }
  });
}
77
mtomis

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]);
    }
});
343
Finbarr

Utilisation du module Node.js readline .

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);
});
68
zswang

utilisez readline ( documentation ). voici un exemple de lecture d'un fichier css, l'analyse d'icônes et leur écriture sur json

var results = [];
  var rl = require('readline').createInterface({
    input: require('fs').createReadStream('./assets/stylesheets/_icons.scss')
  });


  // for every new line, if it matches the regex, add it to an array
  // this is ugly regex :)
  rl.on('line', function (line) {
    var re = /\.icon-icon.*:/;
    var match;
    if ((match = re.exec(line)) !== null) {
      results.Push(match[0].replace(".",'').replace(":",''));
    }
  });


  // readline emits a close event when the file is read.
  rl.on('close', function(){
    var outputFilename = './icons.json';
    fs.writeFile(outputFilename, JSON.stringify(results, null, 2), function(err) {
        if(err) {
          console.log(err);
        } else {
          console.log("JSON saved to " + outputFilename);
        }
    });
  });
7
Blair Anderson

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);
});
5
Gabriel Llamas

file.lines avec package JFile

Pseudo

var JFile=require('jfile');

var myF=new JFile("./data.txt");
myF.lines // ["first line","second line"] ....

N'oubliez pas avant:

npm install jfile --save
5
Abdennour TOUMI

Ceci est une variation de la réponse ci-dessus de @mtomis.

Cela crée un flux de lignes. Il é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 wrapper:

var lineInput = new LineStream(input);

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

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

je veux juste ajouter @finbarr excellente réponse, un petit correctif dans l'exemple asynchrone:

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]);
    }
    done();
});

@MadPhysicist, done () est ce qui libère l'async. appel.

3
HernanFila

Pour lire un gros fichier dans un tableau, vous pouvez lire ligne par ligne ou morceau par morceau.

ligne par ligne reportez-vous à ma réponse ici

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

var lines = [];

var s = fs.createReadStream('filepath')
    .pipe(es.split())
    .pipe(es.mapSync(function(line) {
        //pause the readstream
        s.pause();
        lines.Push(line);
        s.resume();
    })
    .on('error', function(err) {
        console.log('Error:', err);
    })
    .on('end', function() {
        console.log('Finish reading.');
        console.log(lines);
    })
);

chunk by chunk fait référence à cet article

var offset = 0;
var chunkSize = 2048;
var chunkBuffer = new Buffer(chunkSize);
var fp = fs.openSync('filepath', 'r');
var bytesRead = 0;
while(bytesRead = fs.readSync(fp, chunkBuffer, 0, chunkSize, offset)) {
    offset += bytesRead;
    var str = chunkBuffer.slice(0, bytesRead).toString();
    var arr = str.split('\n');

    if(bytesRead = chunkSize) {
        // the last item of the arr may be not a full line, leave it to the next chunk
        offset -= arr.pop().length;
    }
    lines.Push(arr);
}
console.log(lines);
1
Kris Roofe

J'ai eu le même problème, et je l'ai résolu avec le module ligne par ligne

https://www.npmjs.com/package/line-by-line

Au moins pour moi fonctionne comme un charme, à la fois en mode synchrone et asynchrone.

De plus, le problème avec les lignes se terminant pas\n peut être résolu avec l’option suivante: 

{ encoding: 'utf8', skipEmptyLines: false }

Traitement synchrone des lignes:

var LineByLineReader = require('line-by-line'),
    lr = new LineByLineReader('big_file.txt');

lr.on('error', function (err) {
    // 'err' contains error object
});

lr.on('line', function (line) {
    // 'line' contains the current line without the trailing newline character.
});

lr.on('end', function () {
    // All lines are read, file is closed now.
}); 
1
Antoni

Node.js v8 ou version ultérieure utilise une nouvelle fonctionnalité qui convertit une fonction normale en une fonction asynchrone.

util.promisify

C'est une fonctionnalité géniale. Voici l'exemple de l'analyse de 10000 nombres du fichier txt dans un tableau, en comptant les inversions à l'aide du tri par fusion des nombres.

// read from txt file
const util = require('util');
const fs = require('fs')
fs.readFileAsync = util.promisify(fs.readFile);
let result = []

const parseTxt = async (csvFile) => {
  let fields, obj
  const data = await fs.readFileAsync(csvFile)
  const str = data.toString()
  const lines = str.split('\r\n')
  // const lines = str
  console.log("lines", lines)
  // console.log("str", str)

  lines.map(line => {
    if(!line) {return null}
    result.Push(Number(line))
  })
  console.log("result",result)
  return result
}
parseTxt('./count-inversion.txt').then(() => {
  console.log(mergeSort({arr: result, count: 0}))
})
0