Ler um arquivo de texto usando Node.js?

124

Preciso passar um arquivo de texto no terminal e depois ler os dados dele, como posso fazer isso?

node server.js file.txt

Como faço para passar o caminho do terminal, como faço para ler isso do outro lado?

chique
fonte
Se você estiver adicionando mais opções na linha de comando, pode usar o Optimist .
Jess
stackoverflow.com/questions/6156501/… mostra outra maneira de ler um arquivo de texto
Marc Durdin

Respostas:

172

Você vai querer usar o process.argvarray para acessar os argumentos da linha de comando para obter o nome do arquivo e o módulo FileSystem (fs) para ler o arquivo. Por exemplo:

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

Para quebrar isso um pouco, você process.argvnormalmente terá o comprimento dois, o item zero sendo o interpretador de "nó" e o primeiro sendo o script que o nó está executando no momento, itens depois disso foram passados ​​na linha de comando. Depois de obter um nome de arquivo do argv, você pode usar as funções do sistema de arquivos para ler o arquivo e fazer o que quiser com seu conteúdo. O uso de amostra ficaria assim:

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

[Editar] Como @wtfcoder menciona, usar o fs.readFile()método " " pode não ser a melhor ideia porque ele armazenará em buffer todo o conteúdo do arquivo antes de submetê-lo à função de retorno de chamada. Esse armazenamento em buffer poderia potencialmente usar muita memória, mas, mais importante, ele não tira proveito de um dos principais recursos do node.js - E / S assíncrona com eventos.

A maneira de "nó" de processar um arquivo grande (ou qualquer arquivo, na verdade) seria usar fs.read()e processar cada pedaço disponível conforme ele está disponível no sistema operacional. No entanto, ler o arquivo como tal requer que você faça sua própria (possivelmente) análise / processamento incremental do arquivo e alguma quantidade de buffer pode ser inevitável.

matemática
fonte
Incrível, muito obrigado, muito útil. Como posso dividir esses dados por linha?
chique de
10
@fancy: try var lines = data.split(/\r?\n/);, então o array "linhas" terá cada linha.
maerics
1
Isso não é uma boa ideia se o arquivo de texto for grande, já que será todo lido na memória, se você processar, digamos, um arquivo CSV de 1000 MB, olhe em fs.createFilestream, você precisará tomar cuidado com a divisão de linha, pois os blocos de dados não cairá (na maioria dos casos) nos limites da linha (algumas pessoas já criaram soluções - google)
Mâtt Frëëman
1
@wtfcoder: sim, ponto muito bom. Minha intenção era apenas demonstrar o caso simples de ler um arquivo nomeado na linha de comando; obviamente, há muitas sutilezas (especialmente desempenho) que estão além do escopo desta questão.
maerics
Publiquei uma solução para uma questão semelhante para analisar um arquivo muito grande, usando um fluxo síncrono. consulte: stackoverflow.com/questions/16010915/…
Gerard
35

Use fs com nó.

var fs = require('fs');

try {  
    var data = fs.readFileSync('file.txt', 'utf8');
    console.log(data.toString());    
} catch(e) {
    console.log('Error:', e.stack);
}
Ronald
fonte
Observe que esta é a versão síncrona .
Rich Werden
@RichWerden o que você quer dizer com "síncrono" neste contexto?
Json
1
No Node, quando algo é "síncrono", ele para / bloqueia o sistema de fazer qualquer outra coisa. Digamos que você tenha um servidor web de nó - se qualquer outra solicitação entrar enquanto o acima está acontecendo, o servidor não responderá / não poderá responder porque está ocupado lendo o arquivo.
Rich Werden
27

IMHO, fs.readFile()deve ser evitado porque carrega TODOS os arquivos na memória e não chamará o retorno de chamada até que todo o arquivo seja lido.

A maneira mais fácil de ler um arquivo de texto é lê-lo linha por linha. Eu recomendo um 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 ();

Para estruturas de dados complexas como .properties ou arquivos json, você precisa usar um analisador (internamente, também deve usar um leitor de buffer).

Gabriel Llamas
fonte
7
Obrigado por apontar esta técnica. Você está certo que esta pode ser a melhor maneira, mas eu apenas achei que era um pouco confuso no contexto desta pergunta, que eu acho que é uma pergunta sobre um caso de uso pouco exigente. Como apontado acima, se for apenas um pequeno arquivo sendo passado para uma ferramenta de linha de comando, não há razão para não usar fs.readFile()ou fs.readFileSync(). Deve ser um arquivo enorme para causar uma espera perceptível. Um arquivo de configuração JSON como package.json é provável que seja menos de 1 kb, então você pode apenas fs.readFile()e JSON.parse()ele.
John Starr Dewar
1
BufferedReader pode ter alterado sua assinatura. Tive que substituir BufferedReader por BufferedReader, DataReader, onde BufferedReader era o módulo. Consulte github.com/Gagle/Node-BufferedReader
bnieland
13
Vejo que BufferedReader agora está obsoleto.
Marc Rochkind
6

Você pode usar readstream e pipe para ler o arquivo linha por linha sem ler todo o arquivo na memória uma vez.

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
fonte
5

Estou postando um exemplo completo que finalmente consegui funcionar. Aqui estou lendo um arquivo rooms/rooms.txtde um 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
fonte