Odczytać plik tekstowy za pomocą Node.js?

124

Muszę przekazać plik tekstowy do terminala, a następnie odczytać z niego dane, jak mogę to zrobić?

node server.js file.txt

Jak przejść ścieżką od terminala, jak to przeczytać po drugiej stronie?

fantazyjny
źródło
Jeśli zauważysz, że dodajesz więcej opcji w wierszu poleceń, możesz użyć Optimist .
Jess
stackoverflow.com/questions/6156501/… pokazuje inny sposób odczytu pliku tekstowego
Marc Durdin

Odpowiedzi:

172

Będziesz chciał użyć process.argvtablicy, aby uzyskać dostęp do argumentów wiersza poleceń, aby uzyskać nazwę pliku i moduł FileSystem (fs) do odczytania pliku. Na przykład:

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

Aby trochę to załamać, process.argvzwykle będziesz mieć długość równą dwa, przy czym zerowa pozycja to interpreter „węzła”, a pierwsza to skrypt, który aktualnie działa w węźle, kolejne elementy są przekazywane w linii poleceń. Po pobraniu nazwy pliku z argv możesz użyć funkcji systemu plików do odczytania pliku i robienia wszystkiego, co chcesz z jego zawartością. Przykładowe użycie wyglądałoby tak:

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

[Edytuj] Jak wspomina @wtfcoder, użycie metody " fs.readFile()" może nie być najlepszym pomysłem, ponieważ będzie buforować całą zawartość pliku przed przekazaniem go do funkcji wywołania zwrotnego. To buforowanie mogłoby potencjalnie zużywać dużo pamięci, ale co ważniejsze, nie wykorzystuje jednej z podstawowych funkcji node.js - asynchronicznego, zdarzonego wejścia / wyjścia.

Sposobem na „węzeł” przetwarzania dużego pliku (lub tak naprawdę dowolnego pliku) byłoby użycie fs.read()i przetworzenie każdego dostępnego fragmentu, który jest dostępny w systemie operacyjnym. Jednak odczytanie pliku jako takiego wymaga wykonania własnego (prawdopodobnie) przyrostowego analizowania / przetwarzania pliku i pewna ilość buforowania może być nieunikniona.

maerics
źródło
Wspaniale, wielkie dzięki, bardzo pomocne. Jak mogę podzielić te dane według linii?
fantazyjny
10
@fancy: spróbuj var lines = data.split(/\r?\n/);, wtedy tablica "linie" będzie zawierała każdy wiersz.
maerics
1
To nie jest dobry pomysł, jeśli plik tekstowy jest duży, ponieważ zostanie w całości odczytany do pamięci. nie będzie (w większości przypadków) wpadać na granice linii (niektórzy już
wymyślili
1
@wtfcoder: tak, bardzo dobra uwaga. Zamierzałem po prostu zademonstrować prosty przypadek odczytu pliku wymienionego w linii poleceń; istnieje oczywiście wiele subtelności (zwłaszcza wydajności), które wykraczają poza zakres tego pytania.
maerics
Opublikowałem rozwiązanie na podobne pytanie dotyczące parsowania bardzo dużego pliku za pomocą strumienia, synchronicznego. zobacz: stackoverflow.com/questions/16010915/…
Gerard
35

Użyj fs z 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
źródło
Zwróć uwagę, że jest to wersja synchroniczna .
Rich Werden
@RichWerden, co w tym kontekście oznacza „synchroniczny”?
Json
1
W Node, gdy coś jest „synchroniczne”, zatrzymuje / blokuje system przed zrobieniem czegokolwiek innego. Powiedzmy, że masz serwer WWW węzła - jeśli w czasie powyższego pojawią się inne żądania, serwer nie będzie / nie może odpowiedzieć, ponieważ jest zajęty odczytywaniem pliku.
Rich Werden
27

IMHO, fs.readFile()należy unikać, ponieważ ładuje on WSZYSTKIE pliki do pamięci i nie wywoła wywołania zwrotnego, dopóki cały plik nie zostanie odczytany.

Najłatwiejszym sposobem odczytania pliku tekstowego jest przeczytanie go wiersz po wierszu. Polecam 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 ();

W przypadku złożonych struktur danych, takich jak pliki .properties lub json, należy użyć parsera (wewnętrznie powinien również używać buforowanego czytnika).

Gabriel Llamas
źródło
7
Dzięki za wskazanie tej techniki. Masz rację, że to może być najlepszy sposób, ale pomyślałem, że jest to nieco zagmatwane w kontekście tego pytania, które moim zdaniem dotyczy niewymagającego przypadku użycia. Jak wskazano powyżej, jeśli jest to tylko mały plik przesyłany do narzędzia wiersza poleceń, nie ma powodu, aby nie używać fs.readFile()lub fs.readFileSync(). Musi to być ogromny plik, aby spowodować zauważalne oczekiwanie. Plik konfiguracyjny JSON, taki jak package.json, prawdopodobnie będzie miał mniej niż 1 kb, więc możesz po prostu fs.readFile()i JSON.parse()tak.
John Starr Dewar
1
BufferedReader mógł zmienić swój podpis. Musiałem zamienić BufferedReader na BufferedReader, DataReader, gdzie BufferedReader był modułem. Zobacz github.com/Gagle/Node-BufferedReader
bnieland
13
Widzę, że BufferedReader jest teraz przestarzały.
Marc Rochkind
6

Możesz użyć readstream i pipe, aby odczytać plik wiersz po wierszu bez wczytywania całego pliku do pamięci jednorazowo.

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
źródło
5

Zamieszczam kompletny przykład, który w końcu działał. Tutaj czytam plik rooms/rooms.txtze skrypturooms/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
źródło