2015-12-11 16 views
7

muszę przeanalizować pliku linia po linii w następującym formacie z node.js:czytano wiersze z pliku synchronicznie w node.js

13 
13 
0 5 
4 3 
0 1 
9 12 
6 4 
5 4 
0 2 
11 12 
9 10 
0 6 
7 8 
9 11 
5 3 

To przedstawia wykres. Pierwsze dwie linie to liczba krawędzi i wierzchołków, a następnie krawędzie.

mogę wykonać zadanie z czymś takim:

var fs = require('fs'); 
var readline = require('readline'); 
var read_stream = fs.createReadStream(filename); 
var rl = readline.createInterface({ 
    input: read_stream 
}); 
var c = 0; 
var vertexes_number; 
var edges_number; 
var edges = []; 
rl.on('line', function(line){ 
    if (c==0) { 
     vertexes_number = parseInt(line); 
    } else if (c==1) { 
     edges_number = parseInt(line); 
    } else { 
     edges.push(line.split(' ')); 
    } 
    c++; 
}) 
.on('end', function(){ 
    rl.close(); 
}) 

rozumiem tego rodzaju rzeczy nie może być to, co uważano za node.js, ale kaskadowo if w line zwrotnego nie bardzo elegancki wygląd/czytelne dla mnie.

Czy istnieje sposób na odczyt synchronicznie linii ze strumienia, jak w każdym innym języku programowania?

Jestem otwarty na używanie wtyczek, jeśli nie ma wbudowanego rozwiązania.

[EDIT]

Przepraszam, powinienem doprecyzować, że Chciałbym uniknąć załadowanie całego pliku w pamięci wcześniej

+0

https://nodejs.org/api/fs.html#fs_fs_readfilesync_file_options –

+0

tak ładować go 'fs.readFileSync' a następnie analizować je z kodem synchronicznie po rozdzieleniu znakami nowej linii tj' linie = fs.readFileSync ('graph.txt'). split (/ [\ n \ r] /); ' –

Odpowiedz

6

Ten projekt na github.com robi dokładnie to, co potrzebne:

https://github.com/nacholibre/node-readlines

var readlines = require('n-readlines'); 
var liner = new readlines(filename); 

var vertexes_number = parseInt(liner.next().toString('ascii')); 
var edges_number = parseInt(liner.next().toString('ascii')); 
var edges = []; 
var next; 
while (next = liner.next()) { 
    edges.push(next.toString('ascii').split(' ')); 
} 
+0

jest dobrym sposobem na zrobienie tego ze stdin? Używam witryny do przesyłania kodu i nie mogę odczytać/dev/stdin jako pliku. –

+0

Będziesz miał większe szanse na uzyskanie odpowiedzi, jeśli zamieścisz nowe pytanie z większą ilością szczegółów niż komentowaniem tutaj. –

+0

Już wykonane http://stackoverflow.com/questions/43638105/how-to-get-synchronous-readline-or-simulate-it-using-async-in-nodejs –

11

My zwykle część kodu dla takich prostych zadań:

var lines = require('fs').readFileSync(filename, 'utf-8') 
    .split('\n') 
    .filter(Boolean); 

lines to tablica ciągów bez pustych.

+5

Dzięki. Jednak nadal jestem zainteresowany rozwiązaniami lean, które nie ładują całego pliku w pamięci. –

+2

W ten sposób nie można sobie poradzić z dużym plikiem, takim jak plik dziennika linii 10000000, ponieważ można załadować duży plik do pamięci za pomocą bufora, ale metoda nodejs toString nie może obsłużyć zbyt dużego obiektu bufora. – zhuyingda

0

Osobiście lubię używać event-stream do obsługi strumieni. Nie jest to konieczne, ale użyłem go do próbki kodu. To proste, ja analizować na int i umieścić wszystko wewnątrz edges, wtedy gdy odczyt plików odbywa się, biorę pierwszy element wich jest vertexes_number nowy Pierwszym elementem jest edges_number

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

var filename = 'parse-file.txt'; 

var vertexes_number, edges_number; 
var edges = []; 

fs.createReadStream(filename) 
    .pipe(es.split()) // split by lines 
    .pipe(es.map(function (line, next) { 
     // split and convert all to numbers 
     edges.push(line.split(' ').map((n) => +n)); 

     next(null, line); 
    })).pipe(es.wait(function (err, body) { 
     // the first element is an array containing vertexes_number 
     vertexes_number = edges.shift().pop(); 

     // the following element is an array containing edges_number 
     edges_number = edges.shift().pop(); 

     console.log('done'); 
     console.log('vertexes_number: ' + vertexes_number); 
     console.log('edges_number: ' + edges_number); 
     console.log('edges: ' + JSON.stringify(edges, null, 3)); 
    })); 
+0

To jest jak dotąd najlepsza metoda, jeśli nie trzeba ładować całego pliku do pamięci. –

+0

Tak, to jest bardzo dobra tej metody, ale nadal asynchroniczne, pytania określa tryb synchronizacji, nie jest jednak przydatna w tym przypadku. –

1

Dlaczego nie czytać je wszystkie w produkt array, a następnie usuń pierwsze dwa elementy ze splotem. Zakładam, że twój przykład jest znacznie uproszczony, inaczej po prostu przeczytałeś cały plik w pamięci i podzieliłeś go. Jeśli rzeczywisty przypadek przechowuje wielu wykresów i chcesz coś zrobić, gdy każdy z nich jest ładowany na przykład, można umieścić test w przypadku linii

var fs = require('fs'); 
var readline = require('readline'); 
var read_stream = fs.createReadStream(filename); 
var rl = readline.createInterface({ 
    input: read_stream 
}); 

var buffer = []; 

rl.on('line', function(line){ 
    buffer.push(line.split(' ')); 
    //Not sure what your actual requirement is but if you want to do 
    //something like display a graph once one has loaded 
    //obviously need to be able to determine when one has completed loading 
    if (buffer.length == GRAPHLENGTH) { //or some other test 
     displayGraph(buffer); 
     buffer = []; 
    }  
}) 
.on('end', function(){ 
    //or do it here if there is only one graph 
    //displayGraph(buffer); 
    rl.close(); 
}) 

function displayGraph(buffer){ 
    var vertexes_number = parseInt(buffer.splice(0,1)); 
    var edges_number = parseInt(buffer.splice(0,1)); 
    var edges = buffer; 

    //doYourThing(vertexes_number, edges_number, edges); 
} 
+1

Należy wspomnieć, że w przypadku systemu plików nie ma zdarzenia "zakończenie", a raczej "close" jest emitowane na końcu pliku. –