Leggere un file di testo utilizzando Node.js?


Risposte:


172

Ti consigliamo di utilizzare l' process.argvarray per accedere agli argomenti della riga di comando per ottenere il nome del file e il modulo FileSystem (fs) per leggere il file. Per esempio:

// 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)
});

Per process.argvscomporlo un po 'per te di solito avrai lunghezza due, l'elemento zero è l'interprete del "nodo" e il primo è lo script che il nodo sta attualmente eseguendo, gli elementi successivi sono stati passati sulla riga di comando. Dopo aver estratto un nome di file da argv, puoi usare le funzioni del file system per leggere il file e fare quello che vuoi con il suo contenuto. L'utilizzo del campione sarebbe simile a questo:

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

[Modifica] Come menzionato da @wtfcoder, l'utilizzo del fs.readFile()metodo " " potrebbe non essere l'idea migliore perché bufferizzerà l'intero contenuto del file prima di cederlo alla funzione di callback. Questo buffering potrebbe potenzialmente utilizzare molta memoria ma, cosa più importante, non sfrutta una delle funzionalità principali di node.js: I / O asincrono con eventi.

Il modo "nodo" per elaborare un file di grandi dimensioni (o qualsiasi file, in realtà) sarebbe quello di utilizzare fs.read()ed elaborare ogni blocco disponibile così come è disponibile dal sistema operativo. Tuttavia, la lettura del file in quanto tale richiede di eseguire la propria (possibilmente) analisi / elaborazione incrementale del file e una certa quantità di buffering potrebbe essere inevitabile.


Fantastico, grazie mille, molto utile. Come posso suddividere questi dati per riga?
fantasia

10
@fancy: try var lines = data.split(/\r?\n/);, quindi l'array "lines" avrà ogni riga.
maerie

1
Questa non è una buona idea se il file di testo è di grandi dimensioni, poiché verrà letto tutto in memoria, se si elabora un file CSV da 1000 MB guarda fs.createFilestream, sarà necessario fare attenzione con la divisione della riga anche se i blocchi di dati non cadrà (nella maggior parte dei casi) sui confini della linea (alcune persone hanno già trovato soluzioni - google)
Mâtt Frëëman

1
@wtfcoder: sì, ottimo punto. Il mio intento era solo quello di dimostrare il semplice caso di leggere un file denominato sulla riga di comando; ci sono ovviamente molte sottigliezze (specialmente le prestazioni) che esulano dallo scopo di questa domanda.
maerie

Ho pubblicato una soluzione a una domanda simile per l'analisi di un file molto grande, utilizzando un flusso, sincrono. vedi: stackoverflow.com/questions/16010915/…
Gerard

35

Usa fs con node.

var fs = require('fs');

try {  
    var data = fs.readFileSync('file.txt', 'utf8');
    console.log(data.toString());    
} catch(e) {
    console.log('Error:', e.stack);
}

Nota che questa è la versione sincrona .
Rich Werden

@RichWerden cosa intendi per "sincrono" in questo contesto?
Json

1
In Node, quando qualcosa è "sincrono" arresta / blocca il sistema dal fare qualsiasi altra cosa. Supponiamo che tu abbia un server web del nodo: se arrivano altre richieste mentre sta accadendo quanto sopra, il server non / non può rispondere perché è impegnato a leggere il file.
Rich Werden

27

A PARER MIO, fs.readFile() dovrebbe essere evitato perché carica TUTTO il file in memoria e non chiamerà il callback fino a quando tutto il file non sarà stato letto.

Il modo più semplice per leggere un file di testo è leggerlo riga per riga. Consiglio 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 ();

Per strutture di dati complesse come .properties o file json è necessario utilizzare un parser (internamente dovrebbe anche utilizzare un lettore bufferizzato).


7
Grazie per aver sottolineato questa tecnica. Hai ragione sul fatto che questo potrebbe essere il modo migliore, ma ho solo pensato che fosse un po 'confuso nel contesto di questa domanda, che penso sia chiedere un caso d'uso poco impegnativo. Come sottolineato sopra, se si tratta solo di un piccolo file passato a uno strumento da riga di comando, non c'è motivo per non usare fs.readFile()o fs.readFileSync(). Deve essere un file enorme per causare un'attesa notevole. Un JSON file di configurazione come package.json è probabile che sia inferiore a 1 kb, quindi si può semplicemente fs.readFile()ed JSON.parse()esso.
John Starr Dewar

1
BufferedReader potrebbe aver cambiato la sua firma. Ho dovuto sostituire BufferedReader con BufferedReader, DataReader, dove BufferedReader era il modulo. Vedi github.com/Gagle/Node-BufferedReader
bnieland

13
Vedo che BufferedReader è ora deprecato.
Marc Rochkind

6

È possibile utilizzare readstream e pipe per leggere il file riga per riga senza leggere tutto il file in memoria una volta.

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.');
    })
);

5

Sto postando un esempio completo che finalmente ho ottenuto lavorando. Qui sto leggendo in un file rooms/rooms.txtda uno 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);
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.