Lire un fichier texte en utilisant Node.js?

124

Je dois transmettre un fichier texte dans le terminal, puis en lire les données, comment puis-je faire cela?

node server.js file.txt

Comment passer le chemin depuis le terminal, comment lire cela de l'autre côté?

fantaisie
la source
Si vous ajoutez plus d'options sur la ligne de commande, vous pouvez utiliser Optimist .
Jess
stackoverflow.com/questions/6156501/… montre une autre façon de lire un fichier texte
Marc Durdin

Réponses:

172

Vous voudrez utiliser le process.argvtableau pour accéder aux arguments de ligne de commande pour obtenir le nom de fichier et le module FileSystem (fs) pour lire le fichier. Par exemple:

// Make sure we got a filename on the command line.
if (process.argv.length < 3) {
  console.log('Usage: node ' + process.argv[1] + ' FILENAME');
  process.exit(1);
}
// Read the file and print its contents.
var fs = require('fs')
  , filename = process.argv[2];
fs.readFile(filename, 'utf8', function(err, data) {
  if (err) throw err;
  console.log('OK: ' + filename);
  console.log(data)
});

Pour décomposer un peu cela, vous process.argvaurez généralement une longueur de deux, l'élément zéro étant l'interpréteur "node" et le premier étant le script que le nœud est en cours d'exécution, les éléments après cela ont été passés sur la ligne de commande. Une fois que vous avez extrait un nom de fichier d'argv, vous pouvez utiliser les fonctions du système de fichiers pour lire le fichier et faire ce que vous voulez avec son contenu. Un exemple d'utilisation ressemblerait à ceci:

$ node ./cat.js file.txt
OK: file.txt
This is file.txt!

[Edit] Comme le mentionne @wtfcoder, utiliser la fs.readFile()méthode " " n'est peut-être pas la meilleure idée car elle mettra en mémoire tampon tout le contenu du fichier avant de le céder à la fonction de rappel. Cette mise en mémoire tampon pourrait potentiellement utiliser beaucoup de mémoire mais, plus important encore, elle ne tire pas parti de l'une des fonctionnalités de base de node.js - les E / S asynchrones et événementielles.

La manière «nœud» de traiter un gros fichier (ou n'importe quel fichier, en réalité) serait d'utiliser fs.read()et de traiter chaque morceau disponible tel qu'il est disponible à partir du système d'exploitation. Cependant, la lecture du fichier en tant que tel vous oblige à effectuer votre propre analyse / traitement incrémentiel (éventuellement) du fichier et une certaine quantité de mise en mémoire tampon peut être inévitable.

maerics
la source
Génial, merci beaucoup, très utile. Comment pourrais-je diviser ces données par ligne?
fantaisie
10
@fancy: essayez var lines = data.split(/\r?\n/);, alors le tableau "lines" aura chaque ligne.
maerics
1
Ce n'est pas une bonne idée si le fichier texte est volumineux, car il sera tout lu en mémoire, si vous traitez, par exemple, un fichier CSV de 1000 Mo, regardez fs.createFilestream, vous devrez faire attention à la division des lignes car les blocs de données ne tombera pas (dans la plupart des cas) sur les limites de la ligne (certaines personnes ont déjà trouvé des solutions - google)
Mâtt Frëëman
1
@wtfcoder: oui, très bon point. Mon intention était simplement de démontrer le cas simple de la lecture d'un fichier nommé sur la ligne de commande; il y a évidemment de nombreuses subtilités (en particulier les performances) qui sortent du cadre de cette question.
maerics
J'ai posté une solution à une question similaire pour analyser un très gros fichier, en utilisant un flux, synchrone. voir: stackoverflow.com/questions/16010915/...
Gerard
35

Utilisez fs avec node.

var fs = require('fs');

try {  
    var data = fs.readFileSync('file.txt', 'utf8');
    console.log(data.toString());    
} catch(e) {
    console.log('Error:', e.stack);
}
Ronald
la source
Notez qu'il s'agit de la version synchrone .
Rich Werden
@RichWerden qu'entendez-vous par "synchrone" dans ce contexte?
Json
1
Dans Node, quand quelque chose est "synchrone", il arrête / empêche le système de faire autre chose. Disons que vous avez un serveur Web de nœud - si d'autres requêtes arrivent pendant que ce qui précède se produit, le serveur ne répondra pas / ne pourra pas répondre car il est occupé à lire le fichier.
Rich Werden
27

A MON HUMBLE AVIS, fs.readFile() doit être évité car il charge TOUS les fichiers en mémoire et n'appellera pas le rappel tant que tout le fichier n'aura pas été lu.

Le moyen le plus simple de lire un fichier texte est de le lire ligne par ligne. Je recommande un BufferedReader :

new BufferedReader ("file", { encoding: "utf8" })
    .on ("error", function (error){
        console.log ("error: " + error);
    })
    .on ("line", function (line){
        console.log ("line: " + line);
    })
    .on ("end", function (){
        console.log ("EOF");
    })
    .read ();

Pour les structures de données complexes telles que les fichiers .properties ou json, vous devez utiliser un analyseur syntaxique (en interne, il doit également utiliser un lecteur tamponné).

Gabriel Llamas
la source
7
Merci d'avoir signalé cette technique. Vous avez raison de dire que c'est peut-être la meilleure façon, mais je pensais simplement que c'était un peu déroutant dans le contexte de cette question, qui, je pense, concerne un cas d'utilisation peu exigeant. Comme indiqué ci-dessus, s'il ne s'agit que d'un petit fichier transmis à un outil de ligne de commande, il n'y a aucune raison de ne pas utiliser fs.readFile()ou fs.readFileSync(). Il doit s'agir d'un fichier volumineux pour provoquer une attente notable. Un fichier de configuration JSON comme package.json est susceptible d'être de moins de 1 kb, de sorte que vous pouvez juste fs.readFile()et JSON.parse()il.
John Starr Dewar
1
BufferedReader a peut-être changé sa signature. J'ai dû remplacer BufferedReader par BufferedReader, DataReader, où BufferedReader était le module. Voir github.com/Gagle/Node-BufferedReader
bnieland
13
Je vois que BufferedReader est maintenant obsolète.
Marc Rochkind
6

Vous pouvez utiliser readstream et pipe pour lire le fichier ligne par ligne sans lire tout le fichier en mémoire une seule fois.

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

var s = fs.createReadStream(path)
    .pipe(es.split())
    .pipe(es.mapSync(function(line) {
        //pause the readstream
        s.pause();
        console.log("line:", line);
        s.resume();
    })
    .on('error', function(err) {
        console.log('Error:', err);
    })
    .on('end', function() {
        console.log('Finish reading.');
    })
);
Kris Roofe
la source
5

Je poste un exemple complet que j'ai finalement mis au travail. Ici, je lis un fichier à rooms/rooms.txtpartir d'un scriptrooms/rooms.js

var fs = require('fs');
var path = require('path');
var readStream = fs.createReadStream(path.join(__dirname, '../rooms') + '/rooms.txt', 'utf8');
let data = ''
readStream.on('data', function(chunk) {
    data += chunk;
}).on('end', function() {
    console.log(data);
});
iamnotsam
la source