我试图读取一个大文件一行在一次。我在Quora上找到了一个关于这个主题的问题,但我错过了一些联系,把整个事情联系在一起。
var Lazy=require("lazy");
new Lazy(process.stdin)
.lines
.forEach(
function(line) {
console.log(line.toString());
}
);
process.stdin.resume();
我想要弄清楚的是如何一次从文件中读取一行,而不是像本例中那样读取STDIN。
我试着:
fs.open('./VeryBigFile.csv', 'r', '0666', Process);
function Process(err, fd) {
if (err) throw err;
// DO lazy read
}
但这并不奏效。我知道在必要时我可以使用PHP之类的东西,但我想弄清楚这个问题。
我不认为其他答案会起作用,因为文件比我运行它的服务器的内存大得多。
在进行此类操作时,我们必须问自己两个问题:
执行它需要多少内存?
内存消耗是否随着文件大小的增加而急剧增加?
require('fs'). readfilesync()等解决方案将整个文件加载到内存中。这意味着执行操作所需的内存量将几乎等同于文件大小。对于大于50mbs的数据,我们应该避免使用这种方法
通过在函数调用之后放置以下代码行,我们可以很容易地跟踪函数所使用的内存量:
const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(
`The script uses approximately ${Math.round(used * 100) / 100} MB`
);
现在,从大文件中读取特定行最好的方法是使用node的readline。文档中有一些惊人的例子。
你可以自己卷行读卡器。我还没有对这段代码进行基准测试,但它正确地将传入的块流分割成没有结尾的'\n'的行。
var last = "";
process.stdin.on('data', function(chunk) {
var lines, i;
lines = (last+chunk).split("\n");
for(i = 0; i < lines.length - 1; i++) {
console.log("line: " + lines[i]);
}
last = lines[i];
});
process.stdin.on('end', function() {
console.log("line: " + last);
});
process.stdin.resume();
我确实在处理一个快速日志解析脚本时想到了这个,该脚本需要在日志解析期间积累数据,我觉得尝试使用js和node而不是使用perl或bash来做这件事会很好。
无论如何,我确实觉得小的nodejs脚本应该是自包含的,不依赖于第三方模块,所以在读完这个问题的所有答案后,每个答案都使用不同的模块来处理行解析,一个13 SLOC原生nodejs解决方案可能会感兴趣。
function createLineReader(fileName){
var EM = require("events").EventEmitter
var ev = new EM()
var stream = require("fs").createReadStream(fileName)
var remainder = null;
stream.on("data",function(data){
if(remainder != null){//append newly received data chunk
var tmp = new Buffer(remainder.length+data.length)
remainder.copy(tmp)
data.copy(tmp,remainder.length)
data = tmp;
}
var start = 0;
for(var i=0; i<data.length; i++){
if(data[i] == 10){ //\n new line
var line = data.slice(start,i)
ev.emit("line", line)
start = i+1;
}
}
if(start<data.length){
remainder = data.slice(start);
}else{
remainder = null;
}
})
stream.on("end",function(){
if(null!=remainder) ev.emit("line",remainder)
})
return ev
}
//---------main---------------
fileName = process.argv[2]
lineReader = createLineReader(fileName)
lineReader.on("line",function(line){
console.log(line.toString())
//console.log("++++++++++++++++++++")
})