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.
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);
}
});
}
var fs = require('fs');
var array = fs.readFileSync('file.txt').toString().split("\n");
for(i in array) {
console.log(array[i]);
}
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]);
}
});
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);
});
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);
}
});
});
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);
});
file.lines
avec package JFile
var JFile=require('jfile');
var myF=new JFile("./data.txt");
myF.lines // ["first line","second line"] ....
N'oubliez pas avant:
npm install jfile --save
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
});
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.
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);
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.
});
Node.js v8 ou version ultérieure utilise une nouvelle fonctionnalité qui convertit une fonction normale en une fonction asynchrone.
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}))
})