从Node.js中的文件同步读取行

时间:2015-12-11 11:59:45

标签: javascript node.js

我需要使用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

它代表一个图表。前两行是边和顶点的数量,后面是边。

我可以通过以下方式完成任务:

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

我理解这类事情可能不是Node.js的想法,但if回调中的级联line对我来说看起来并不优雅/可读。

有没有办法像其他编程语言一样从流中读取同步行?

如果没有内置解决方案,我可以使用插件。

[编辑]

抱歉,我应该更清楚我想避免事先将整个文件加载到内存中

4 个答案:

答案 0 :(得分:30)

这些简单任务的常用代码部分:

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

lines是一个没有空字符串的字符串数组。

答案 1 :(得分:10)

github.com上的这个项目正是我所需要的:

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

答案 2 :(得分:1)

为什么不将它们全部读入数组,然后用splice取出前两个元素。我假设您的示例非常简化,否则您只需将整个文件读入内存并将其拆分。如果您的实际案例存储多个图表,并且您希望在每个图表加载时执行某些操作,则可以在行事件中进行测试

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('close', 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);
}

答案 3 :(得分:0)

就个人而言,我喜欢使用event-stream来处理流。这里没有必要,但我用它代码示例。这很简单,我解析为int并将所有内容放在edges中,然后当文件读取完成时,我取第一个元素是vertexes_number,新的第一个元素是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));
    }));