Próbuję odczytać duży plik po jednym wierszu na raz. Znalazłem pytanie na temat Quory, które dotyczyło tego tematu, ale brakuje mi niektórych powiązań, aby wszystko to połączyć.
var Lazy=require("lazy");
new Lazy(process.stdin)
.lines
.forEach(
function(line) {
console.log(line.toString());
}
);
process.stdin.resume();
Chciałbym dowiedzieć się, jak mógłbym czytać jedną linię na raz z pliku zamiast STDIN, jak w tym przykładzie.
Próbowałem:
fs.open('./VeryBigFile.csv', 'r', '0666', Process);
function Process(err, fd) {
if (err) throw err;
// DO lazy read
}
ale to nie działa. Wiem, że w mgnieniu oka mogłem wrócić do używania czegoś takiego jak PHP, ale chciałbym to rozgryźć.
Nie sądzę, aby druga odpowiedź działała, ponieważ plik jest znacznie większy niż serwer, na którym go uruchamiam, ma pamięć.
javascript
node.js
file-io
lazy-evaluation
Alex C.
źródło
źródło
fs.readSync()
. Możesz czytać oktety binarne w buforze, ale nie ma łatwego sposobu na radzenie sobie z częściowymi znakami UTF-8 lub UTF-16 bez sprawdzania bufora przed przetłumaczeniem go na ciągi JavaScript i skanowanie w poszukiwaniu EOL.Buffer()
Typ nie ma tak bogaty zestaw funkcji, które działają na jego wystąpień jako natywne strun, ale natywne łańcuchy nie mogą zawierać dane binarne. Wydaje mi się, że brak wbudowanego sposobu odczytu linii tekstu z dowolnych uchwytów plików to prawdziwa luka w pliku node.js.if (line.length==1 && line[0] == 48) special(line);
node
dokumentach API github.com/nodejs/node/pull/4609Odpowiedzi:
Od wersji Node.js v0.12 i od wersji Node.js v4.0.0 istnieje stabilny moduł podstawowy readline . Oto najprostszy sposób odczytu linii z pliku, bez żadnych zewnętrznych modułów:
Lub alternatywnie:
Ostatni wiersz jest odczytywany poprawnie (od Node v0.12 lub nowszego), nawet jeśli nie ma końcowego
\n
.AKTUALIZACJA : ten przykład został dodany do oficjalnej dokumentacji API Node .
źródło
rl.on('close', cb)
W przypadku tak prostej operacji nie powinno być żadnej zależności od modułów innych firm. Spokojnie.
źródło
line
zdarzenia przychodzą dopiero po trafieniu\n
, tzn. wszystkie alternatywy są pominięte (patrz unicode.org/reports/tr18/#Line_Boundaries ). # 2, dane po ostatnim\n
są dyskretnie ignorowane (patrz stackoverflow.com/questions/18450197/… ). nazwałbym to rozwiązanie niebezpiecznym, ponieważ działa ono na 99% wszystkich plików i na 99% danych, ale w pozostałych przypadkach kończy się niepowodzeniem . za każdym razem, gdy to robiszfs.writeFileSync( path, lines.join('\n'))
, zapisujesz plik, który zostanie tylko częściowo odczytany przez powyższe rozwiązanie.readline
zachowuje opakowaniu w naprawdę dziwnych sposobów na doświadczonego Unix / Linux programista.rd.on("close", ..);
może być używany jako oddzwanianie (występuje, gdy wszystkie linie są odczytywane)Nie musisz do
open
pliku, ale zamiast tego musisz utworzyćReadStream
.fs.createReadStream
Następnie przekaż ten strumień do
Lazy
źródło
new lazy(fs.createReadStream('...')).lines.forEach(function(l) { /* ... */ }).join(function() { /* Done */ })
new lazy(...).lines.forEach(...).on('end', function() {...})
.on('end'...
po.forEach(...)
, podczas gdy w rzeczywistości wszystko zachowywał się zgodnie z oczekiwaniami, kiedy związany zdarzenie pierwszy .jest bardzo ładny moduł do odczytu pliku linia po linii, nazywa się on czytnikiem linii
dzięki temu po prostu piszesz:
możesz nawet iterować plik za pomocą interfejsu w stylu Java, jeśli potrzebujesz większej kontroli:
źródło
process/stdin
). Przynajmniej, jeśli to możliwe, z pewnością nie jest to oczywiste po przeczytaniu kodu i próbie.readline
modułu podstawowego .function(reader)
ifunction(line)
powinno być:function(err,reader)
ifunction(err,line)
.line-reader
odczytuje plik asynchronicznie. Synchroniczną alternatywą jestline-reader-sync
źródło
Aktualizacja w 2019 r
Niesamowity przykład opublikowano już w oficjalnej dokumentacji Nodejsa. tutaj
Wymaga to zainstalowania najnowszego oprogramowania Nodejs na twoim komputerze. > 11,4
źródło
await
s międzycreateInterface()
wywołaniem a początkiemfor await
pętli, w tajemniczy sposób utracisz linie od początku pliku.createInterface()
natychmiast zaczyna emitować linie za scenami, a iterator asynchroniczny utworzony domyślnie zaconst line of rl
pomocą nie może rozpocząć nasłuchiwania tych linii, dopóki nie zostanie utworzony.Stary temat, ale to działa:
Prosty. Nie potrzeba zewnętrznego modułu.
źródło
readline is not defined
lubfs is not defined
, dodajvar readline = require('readline');
i,var fs = require('fs');
aby to zadziałało. W przeciwnym razie słodki, słodki kod. Dzięki.Zawsze możesz rzucić własny czytnik linii. Jeszcze nie przetestowałem tego fragmentu, ale poprawnie dzieli on przychodzący strumień fragmentów na linie bez końcowego „\ n”
Wpadłem na to podczas pracy nad szybkim skryptem parsującym dziennik, który musiał gromadzić dane podczas parsowania dziennika i czułem, że fajnie byłoby spróbować to zrobić przy użyciu js i node zamiast perla lub bash.
W każdym razie uważam, że małe skrypty nodejs powinny być samodzielne, a nie polegać na modułach stron trzecich, więc po przeczytaniu wszystkich odpowiedzi na to pytanie, z których każdy używa różnych modułów do parsowania linii, interesujące może być nodejskie rozwiązanie 13 SLOC.
źródło
stdin
... tylko, jeśli czegoś mi brakuje.ReadStream
pomocąfs.createReadStream('./myBigFile.csv')
i używać go zamiaststdin
readline
modułu podstawowego .Z modułem nośnym :
źródło
var inStream = fs.createReadStream('input.txt', {flags:'r'});
Ale twoja składnia jest czystsza niż udokumentowana metoda użycia .on ():carrier.carry(inStream).on('line', function(line) { ...
\r\n
i\n
kończyć linie. Jeśli kiedykolwiek będziesz musiał poradzić sobie z plikami testowymi w stylu MacOS sprzed OS X, były one używane\r
i operator nie obsługuje tego. Co zaskakujące, nadal istnieją takie pliki unoszące się na wolności. Może być również konieczne jawne potraktowanie BOM Unicode (znak kolejności bajtów), jest to używane na początku plików tekstowych w strefie wpływów MS Windows.readline
modułu podstawowego .Skończyło się na masywnym przecieku pamięci przy użyciu Lazy do odczytu linii po linii podczas próby przetworzenia tych linii i zapisania ich do innego strumienia ze względu na sposób, w jaki działa odpływ / pauza / wznowienie w węźle (patrz: http: // elegantcode .com / 2011/04/06 / taking-baby-steps-with-node-js-pumping-data-between-streams / (I love this guy btw)). Nie spojrzałem wystarczająco uważnie na Lazy'ego, aby dokładnie zrozumieć, dlaczego, ale nie mogłem wstrzymać strumienia odczytu, aby pozwolić na drenaż bez wyjścia Lazy'ego.
Napisałem kod do przetwarzania ogromnych plików csv na dokumenty XML, możesz zobaczyć kod tutaj: https://github.com/j03m/node-csv2xml
Jeśli uruchomisz poprzednie wersje z linią Lazy, wycieka. Najnowsza wersja wcale nie wycieka i prawdopodobnie możesz użyć jej jako podstawy dla czytnika / procesora. Chociaż mam tam trochę niestandardowych rzeczy.
Edycja: Myślę, że powinienem również zauważyć, że mój kod z Lazy działał dobrze, dopóki nie znalazłem pisania wystarczająco dużych fragmentów xml, które wyczerpują / wstrzymują / wznawiają z konieczności. W przypadku mniejszych kawałków było w porządku.
źródło
readline
modułu podstawowego .Edytować:
Użyj strumienia transformacji .
Za pomocą BufferedReadera możesz czytać wiersze.
źródło
readline
modułu podstawowego .Od czasu opublikowania mojej oryginalnej odpowiedzi stwierdziłem, że split jest bardzo łatwym w użyciu modułem węzła do odczytu linii w pliku; Który akceptuje również parametry opcjonalne.
Nie testowałem na bardzo dużych plikach. Daj nam znać, jeśli tak.
źródło
Byłem sfrustrowany brakiem kompleksowego rozwiązania tego problemu, więc przygotowałem własną próbę ( git / npm ). Skopiowana lista funkcji:
NIH? Ty decydujesz :-)
źródło
źródło
data
wezwanie dostream.on("data")
może zacząć się, czy skończyć, tylko częścią wielobajtowej postaci UTF-8, na przykład takiej,ა
któraU+10D0
składa się z trzech bajtówe1
83
90
readline
modułu podstawowego .Chciałem rozwiązać ten sam problem, w zasadzie w Perlu:
Mój przypadek użycia był tylko samodzielnym skryptem, a nie serwerem, więc synchronizacja była w porządku. To były moje kryteria:
Jest to dla mnie projekt, aby zapoznać się z kodem typu skryptowego niskiego poziomu w node.js i zdecydować, jak opłacalne jest to zastąpienie innych języków skryptowych, takich jak Perl.
Po zaskakującym nakładzie pracy i kilku fałszywych startach jest to kod, który wymyśliłem. Jest dość szybki, ale mniej trywialny, niż bym się spodziewał: (rozwidl go na GitHub)
Prawdopodobnie można go jeszcze wyczyścić, to wynik prób i błędów.
źródło
W większości przypadków powinno to wystarczyć:
źródło
Czytnik linii oparty na generatorze: https://github.com/neurosnap/gen-readlines
źródło
Jeśli chcesz przeczytać plik wiersz po wierszu i zapisać go w innym:
źródło
Miałem ten sam problem i wymyśliłem powyższe rozwiązanie, które wygląda podobnie dla innych, ale jest aSync i może bardzo szybko odczytywać duże pliki
Mam nadzieję, że to pomoże
źródło
Mam mały moduł, który robi to dobrze i jest używany w wielu innych projektach npm readline. Uwaga: w węźle v10 jest natywny moduł readline, więc ponownie opublikowałem mój moduł jako linebyline https://www.npmjs.com/package/ linebyline
jeśli nie chcesz korzystać z modułu, funkcja jest bardzo prosta:
źródło
Innym rozwiązaniem jest uruchomienie logiki za pomocą sekwencyjnego modułu wykonującego nsynjs . Czyta plik linia po linii za pomocą modułu readline węzła i nie używa obietnic ani rekurencji, dlatego nie zawiedzie dużych plików. Oto jak będzie wyglądał kod:
Powyższy kod oparty jest na tym przykładzie: https://github.com/amaksr/nsynjs/blob/master/examples/node-readline/index.js
źródło
Dwa pytania, które musimy sobie zadać podczas wykonywania takich operacji, to:
Rozwiązania takie jak
require('fs').readFileSync()
ładują cały plik do pamięci. Oznacza to, że ilość pamięci wymagana do wykonania operacji będzie prawie równa rozmiarowi pliku. Powinniśmy tego unikać w przypadku czegoś większego niż50mbs
Możemy łatwo śledzić ilość pamięci używanej przez funkcję, umieszczając następujące wiersze kodu po wywołaniu funkcji:
W tej chwili najlepszym sposobem na odczyt poszczególnych linii z dużego pliku jest użycie readline węzła . Dokumentacja zawiera niesamowite przykłady .
Chociaż nie potrzebujemy do tego żadnego modułu innej firmy. Ale jeśli piszesz kod korporacyjny, musisz obsłużyć wiele przypadkowych przypadków. Musiałem napisać bardzo lekki moduł o nazwie Apick File Storage aby obsłużyć wszystkie te przypadki brzegowe.
Moduł przechowywania plików Apick: https://www.npmjs.com/package/apickfs Dokumentacja: https://github.com/apickjs/apickFS#readme
Przykładowy plik: https://1drv.ms/t/s!AtkMCsWInsSZiGptXYAFjalXOpUx
Przykład: zainstaluj moduł
Ta metoda została pomyślnie przetestowana z gęstymi plikami do 4 GB.
big.text to gęsty plik tekstowy z 163 845 liniami i ma 124 Mb. Skrypt do odczytu 10 różnych wierszy z tego pliku zużywa tylko około 4,63 MB pamięci. I za darmo analizuje prawidłowy JSON na Objects lub Arrays. 🥳 Niesamowite !!
Możemy odczytać jedną linię pliku lub setki linii pliku przy bardzo małym zużyciu pamięci.
źródło
używam tego:
użyj tej funkcji w strumieniu i nasłuchuj emitowanych zdarzeń linii.
gr-
źródło
Chociaż prawdopodobnie powinieneś użyć
readline
modułu, jak sugeruje górna odpowiedź,readline
wydaje się być zorientowany raczej na interfejsy linii poleceń niż na czytanie linii. Jest również nieco bardziej nieprzejrzysty w zakresie buforowania. (Każdy, kto potrzebuje czytnika zorientowanego na przesyłanie strumieniowe, prawdopodobnie będzie chciał dostosować rozmiary buforów). Moduł readline ma ~ 1000 linii, podczas gdy ten, ze statystykami i testami, ma 34.Oto jeszcze krótsza wersja, bez statystyk, w 19 liniach:
źródło
źródło
Opieram całą logikę codziennego przetwarzania linii jako moduł npm: line-kit https://www.npmjs.com/package/line-kit
źródło
Używam poniżej kodu linii odczytu po sprawdzeniu, że nie jest to katalog i nie ma go na liście plików, nie trzeba go sprawdzać.
źródło
Przejrzałem wszystkie powyższe odpowiedzi, wszystkie wykorzystują bibliotekę innej firmy do rozwiązania tego problemu. Ma proste rozwiązanie w interfejsie API Node. na przykład
źródło