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
Read lines synchronously from file in Node.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 if
in the line
callback does not really look elegant / readable to me.
我明白这样的事情可能不是什么Node.js的被认为对的,但级联if
的line
回调并没有真正看起来优雅/读给我。
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);
lines
is 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-stream
to 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));
}));