Javascript 在Node.JS中一次读取N行大文件
我有一个65000000行的文件,大约2gb大小 我想一次读取N行中的文件,执行db insert操作,然后读取下一个N,在本例中,N是1000。插入顺序无关紧要,所以同步是可以的 最好的方法是什么?我只发现要么一次加载一行,要么将整个文件读入内存。下面的示例代码,我一直在使用它一次读取一行文件:Javascript 在Node.JS中一次读取N行大文件,javascript,arrays,node.js,Javascript,Arrays,Node.js,我有一个65000000行的文件,大约2gb大小 我想一次读取N行中的文件,执行db insert操作,然后读取下一个N,在本例中,N是1000。插入顺序无关紧要,所以同步是可以的 最好的方法是什么?我只发现要么一次加载一行,要么将整个文件读入内存。下面的示例代码,我一直在使用它一次读取一行文件: var singleFileParser = (file, insertIntoDB) => { var lr = new LineByLineReader(file); lr.
var singleFileParser = (file, insertIntoDB) => {
var lr = new LineByLineReader(file);
lr.on('error', function(err) {
// 'err' contains error object
console.error(err);
console.error("Error reading file!");
});
lr.on('line', function(line) {
insertIntoDB(line);
// 'line' contains the current line without the trailing newline character.
});
lr.on('end', function() {
// All lines are read, file is closed now.
});
};
像这样的事情应该可以
var cnt = 0;
var tenLines = [];
lr.on('line', function(line) {
tenLines.push(line);
if (++cnt >= 10) {
lr.pause();
// prepare your SQL statements from tenLines
dbInsert(<yourSQL>, function(error, returnVal){
cnt = 0;
tenLines = [];
lr.resume();
});
}
});
var cnt=0;
var tenLines=[];
lr.on(线路),功能(线路){
十行。推(行);
如果(++cnt>=10){
lr.pause();
//从十行中准备SQL语句
dbInsert(,函数(错误,returnVal){
cnt=0;
十行=[];
lr.resume();
});
}
});
某个人一次只能解析一行。所以,如果你一次想要10个,那么你只需要一次收集一个,直到你收集了10个,然后处理10个
我不认为Jarek的代码工作得很好,所以这里有一个不同的版本,它将10行数据收集到一个数组中,然后调用dbInsert()
:
var tenLines=[];
lr.on(线路),功能(线路){
十行。推(行);
如果(tenLines.length==10){
lr.pause();
dbInsert(,函数(错误,returnVal){
如果(错误){
//这里有些错误处理
}
十行=[];
lr.resume();
});
}
});
//处理十行缓冲区中的最后一组行(如果有)
lr.on('end',function(){
if(tenLines.length!==0){
//处理最后一组行
dbInsert(…);
}
});
Jarek的版本似乎对每一个
行事件调用dbInsert()
,而不仅仅是每10行事件调用一次,如果它们不是10行的完美倍数,则不会处理文件末尾的任何剩余行。这是我在异步函数中的解决方案:
let multipleLines = [];
const filepath = '<file>';
const numberLines = 50;
const lineReader = require('readline').createInterface({
input: require('fs').createReadStream(filepath)
});
// process lines by numberLines
for await (const line of lineReader) {
multipleLines.push(line);
if (multipleLines.length === numberLines) {
await dbInsert();
multipleLines = [];
}
}
// process last set of lines (if any)
if (multipleLines.length !== 0) {
await dbInsert();
}
let multipleline=[];
常量文件路径=“”;
常数数线=50;
const lineReader=require('readline')。createInterface({
输入:require('fs')。createReadStream(文件路径)
});
//数字线工艺生产线
用于等待(读线器的常量行){
多线推(线);
if(multipleLines.length==numberLines){
等待dbInsert();
多线=[];
}
}
//处理最后一组行(如果有)
if(multipleLines.length!==0){
等待dbInsert();
}
您是否考虑过编写一个小脚本,将文件分成更小的部分?只是一个想法。@JonLuca-Yep,所有的行都必须由某人一次解析一行,所以如果你想在执行数据库操作之前解析10行,那么只需收集行,直到有10行,然后再执行数据库操作。太好了,工作得非常好!真不敢相信我竟然没有想到这一点。还在考虑线程安全,忘记了节点是单线程的。谢谢@乔卢卡-嗯。我认为这是一个比赛条件。调用dbInsert()
时,可能是在将来某个时候调用完成回调之前。这意味着其他(…)上的lr.on
事件可以流动。然后,完成回调将到达,您将扰乱cnt和tenLines阵列。在开始db操作之前,您需要获取您的十行(可能将它们复制到另一个数组中),并将cnt设置回零,将数组设置回空。我看不到这一点。我假设调用lr.pause()
时,在调用lr.on(…)
之前,不会在lr.resume()
上触发任何事件。所以,下次你看到一行时,它应该在cnt=0之后;十行=[]代码>已在回调中执行。让我想想。好吧,我没有看到lr.pause()
(这是一种半隐藏的编码方式)。但是,如何不在每个行
事件上调用dbInsert()
?您不需要一个if
语句,它在cnt==10
时只调用dbInsert()
?是的,它有这个问题。我做了和你一样的改变。谢谢@JonLuca-我做了额外的编辑,因为前面的代码没有处理最后一组行,除非它恰好是10的整数倍。我还删除了cnt
变量,因为它不是必需的,因为我们可以使用tenLines.length
作为计数器。
let multipleLines = [];
const filepath = '<file>';
const numberLines = 50;
const lineReader = require('readline').createInterface({
input: require('fs').createReadStream(filepath)
});
// process lines by numberLines
for await (const line of lineReader) {
multipleLines.push(line);
if (multipleLines.length === numberLines) {
await dbInsert();
multipleLines = [];
}
}
// process last set of lines (if any)
if (multipleLines.length !== 0) {
await dbInsert();
}