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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34223065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:04:08  来源:igfitidea点击:

Read lines synchronously from file in Node.js

javascriptnode.js

提问by Andrea Casaccia

I need to parse a file line by line in the following format with 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

It represents a graph. The first two lines are the number of edges and vertexes, followed by the edges.

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

I can accomplish the task with something like:

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

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

I understand this kind of things might not be what Node.js was thought for, but the cascaded ifin the linecallback does not really look elegant / readable to me.

我明白这样的事情可能不是什么Node.js的被认为对的,但级联ifline回调并没有真正看起来优雅/读给我。

Is there a way to read synchronously lines from a stream like in every other programming language?

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

I'm open to use plugins if there is not a built-in solution.

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

[EDIT]

[编辑]

Sorry, I should have made clearer that I would like to avoid loading the whole file in memory beforehand

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

采纳答案by Andrea Casaccia

This project on github.com does exactly what I needed:

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

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

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

回答by Alexey Ten

My usual code part for such simple tasks:

我通常用于此类简单任务的代码部分:

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

linesis an array of strings without empty ones.

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

回答by Dave Pile

Why not read them all into an array and then take out the first two elements with splice. I assume that your example is much simplified or else you would just read the whole file into memory and split it. If your actual case stores multiple graphs and you want to do something when each one is loaded for instance, you can put a test in your line event

为什么不把它们全部读入一个数组,然后用 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);
}

回答by Shanoor

Personally, I like to use event-streamto deal with streams. It's not necessary here but I used it for the code sample. It's simple, I parse to int and put everything inside edges, then when the file reading is done, I take the first element wich is vertexes_number, the new first element is edges_number

就我个人而言,我喜欢用它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));
    }));