Javascript Node.js:计算文件中的行数
我有大的文本文件,范围在Javascript Node.js:计算文件中的行数,javascript,node.js,Javascript,Node.js,我有大的文本文件,范围在30MB和10GB之间。如何使用Node.js计算文件中的行数 我有以下限制: 整个文件不需要写入内存 执行该任务不需要子进程 您可以使用wc var exec = require('child_process').exec; exec('wc /path/to/file', function (error, results) { console.log(results); }); 不使用wc的解决方案: var i; var count = 0; requ
30MB
和10GB
之间。如何使用Node.js
计算文件中的行数
我有以下限制:
- 整个文件不需要写入内存
- 执行该任务不需要子进程
wc
var exec = require('child_process').exec;
exec('wc /path/to/file', function (error, results) {
console.log(results);
});
不使用wc的解决方案:
var i;
var count = 0;
require('fs').createReadStream(process.argv[2])
.on('data', function(chunk) {
for (i=0; i < chunk.length; ++i)
if (chunk[i] == 10) count++;
})
.on('end', function() {
console.log(count);
});
自从iojs 1.5.0以来,就有了
Buffer#indexOf()
方法,使用它与Andrey Sidorov的答案进行比较:
ubuntu@server:~$ wc logs
7342500 27548750 427155000 logs
ubuntu@server:~$ time wc -l logs
7342500 logs
real 0m0.180s
user 0m0.088s
sys 0m0.084s
ubuntu@server:~$ nvm use node
Now using node v0.12.1
ubuntu@server:~$ time node countlines.js logs
7342500
real 0m2.559s
user 0m2.200s
sys 0m0.340s
ubuntu@server:~$ nvm use iojs
Now using node iojs-v1.6.2
ubuntu@server:~$ time iojs countlines2.js logs
7342500
real 0m1.363s
user 0m0.920s
sys 0m0.424s
ubuntu@server:~$ cat countlines.js
var i;
var count = 0;
require('fs').createReadStream(process.argv[2])
.on('data', function(chunk) {
for (i=0; i < chunk.length; ++i)
if (chunk[i] == 10) count++;
})
.on('end', function() {
console.log(count);
});
ubuntu@server:~$ cat countlines2.js
var i;
var count = 0;
require('fs').createReadStream(process.argv[2])
.on('data', function(chunk) {
var index = -1;
while((index = chunk.indexOf(10, index + 1)) > -1) count++
})
.on('end', function() {
console.log(count);
});
ubuntu@server:~$
ubuntu@server:~$wc日志
7342500 27548750 427155000原木
ubuntu@server:~$time wc-l日志
7342500原木
实际0.180s
用户0m0.088s
系统0m0.084s
ubuntu@server:~$nvm使用节点
现在使用节点v0.12.1
ubuntu@server:~$time节点countlines.js日志
7342500
实际0m2.559s
用户0m2.200s
sys 0m0.340s
ubuntu@server:~$nvm使用iojs
现在使用节点iojs-v1.6.2
ubuntu@server:~$time iojs countlines2.js日志
7342500
实0m1.363s
用户0m0.920s
系统0m0.424s
ubuntu@server:~$cat countlines.js
var i;
var计数=0;
require('fs').createReadStream(process.argv[2])
.on('data',函数(块){
对于(i=0;i-1)计数++
})
.on('end',function(){
控制台日志(计数);
});
ubuntu@server:~$
这里是另一种不用太多嵌套的方法
var fs = require('fs');
filePath = process.argv[2];
fileBuffer = fs.readFileSync(filePath);
to_string = fileBuffer.toString();
split_lines = to_string.split("\n");
console.log(split_lines.length-1);
也可以使用indexOf():
有一个名为npm的模块。我一直在使用smallish(我们可以使用它让VM找到换行符:
function countFileLines(filePath){
return new Promise((resolve, reject) => {
let lineCount = 0;
fs.createReadStream(filePath)
.on("data", (buffer) => {
let idx = -1;
lineCount--; // Because the loop will run once for idx=-1
do {
idx = buffer.indexOf(10, idx+1);
lineCount++;
} while (idx !== -1);
}).on("end", () => {
resolve(lineCount);
}).on("error", reject);
});
};
此解决方案的作用是使用.indexOf
查找第一个换行符的位置。它增加行数
,然后查找下一个位置。.indexOf
的第二个参数告诉我们从何处开始查找换行符。这样我们就跳过了缓冲区的大块。while循环将运行0每行换行一次,再加一次
我们让节点运行时为我们执行搜索,这是在较低级别上实现的,应该更快
在我的系统上,这大约是在大文件(111 MB)的缓冲区长度上运行
for
循环速度的两倍。我找到的最佳解决方案是使用Promission、async和await。这也是Wait如何履行承诺的一个示例:
#!/usr/bin/env node
const fs = require('fs');
const readline = require('readline');
function main() {
function doRead() {
return new Promise(resolve => {
var inf = readline.createInterface({
input: fs.createReadStream('async.js'),
crlfDelay: Infinity
});
var count = 0;
inf.on('line', (line) => {
console.log(count + ' ' + line);
count += 1;
});
inf.on('close', () => resolve(count));
});
}
async function showRead() {
var x = await doRead();
console.log('line count: ' + x);
}
showRead();
}
main();
如果您使用节点8及更高版本,则可以使用此异步/等待模式
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function fileLineCount({ fileLocation }) {
const { stdout } = await exec(`cat ${fileLocation} | wc -l`);
return parseInt(stdout);
};
// Usage
async someFunction() {
const lineCount = await fileLineCount({ fileLocation: 'some/file.json' });
}
wc-l文件
…“使用NodeJS”--这个要求背后有什么真正的技术原因吗?我确信wc
比任何“本机”都要快nodejs解决方案您可以数一数行--@zerkms您使用的是哪种shell脚本语言?您的基准测试不是很有说服力,因为您运行的文件不是结构化的行,因此不能代表OP想要处理的文件类型。行if(chunk[i]=10)count++;
在分析文本文件时比分析二进制视频文件时执行的频率要高得多。我没有100mb的文本文件:)即使是类似的100mb文本文件,但换行数为10倍,我也不期望有任何不同——这是相同的线性搜索,迭代每个缓冲区块中的每个字节。这说明我是无辜的,但“chunk[I]==10”是什么意思?我猜如果区块等于10,那就是一个新行,但是为什么要和数字10比较呢?10是“新行”字符的ascii码。为了更好的可读性,您可以提前几行const LINE\u FEED='\n'.charCodeAt(0)
,然后if(chunk[i]==LINE\u FEED)count++
您的实现被关闭了一次。例如,如果您的文件有两行,那么它只有一行新行,因此您的脚本将记录1
wc
是一个特定于bash的命令,并且可能无法在windows环境中工作,例如wc-l
仅计算行数wc-l path/to/file
将给出行数和文件名。要仅获取行数,请使用wc-l
如果您喜欢这样做,请尝试sed-n'$='/path/To/file
它只返回行数,您可以在其上应用函数parseInt
来获取您的行数。parseInt(execSync('wc-l
虽然这个代码片段可以解决这个问题,但它确实有助于提高文章的质量。请记住,您将在将来回答读者的问题,这些人可能不知道您的代码建议的原因。还请尽量不要用解释性注释挤满你的代码,这会降低代码和解释的可读性!此解决方案需要将文件加载到内存中。我建议不要这样做。使用wc
的答案并不正确,因为wc
优化了文件流。与一年前发布相同内容的人相比,答案也没有增加任何有价值的内容。问题特别指出,文件的大小从30MB到10GB不等。此解决方案在处理之前将整个文件读入内存。这可能会导致代码崩溃,因为JavaScript可能会耗尽内存。与这里展示的其他解决方案相比,这是最好的解决方案!这个答案太神奇了。应该在上面。计算200MB文件上的行数只花了200毫秒。我可以很高兴地确认,这种方法在非常大的文件(16GB)上也表现得非常好。如果有人能从第行开始解释它是如何工作的,那么让idx=-1
就太棒了。非常感谢。对于10gb文件,至少可以说这不是很好的性能。这是一个简单而好的方法,但只适用于小文件!如果文件是10GB文件,请使用Scrip
function countFileLines(filePath){
return new Promise((resolve, reject) => {
let lineCount = 0;
fs.createReadStream(filePath)
.on("data", (buffer) => {
let idx = -1;
lineCount--; // Because the loop will run once for idx=-1
do {
idx = buffer.indexOf(10, idx+1);
lineCount++;
} while (idx !== -1);
}).on("end", () => {
resolve(lineCount);
}).on("error", reject);
});
};
#!/usr/bin/env node
const fs = require('fs');
const readline = require('readline');
function main() {
function doRead() {
return new Promise(resolve => {
var inf = readline.createInterface({
input: fs.createReadStream('async.js'),
crlfDelay: Infinity
});
var count = 0;
inf.on('line', (line) => {
console.log(count + ' ' + line);
count += 1;
});
inf.on('close', () => resolve(count));
});
}
async function showRead() {
var x = await doRead();
console.log('line count: ' + x);
}
showRead();
}
main();
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function fileLineCount({ fileLocation }) {
const { stdout } = await exec(`cat ${fileLocation} | wc -l`);
return parseInt(stdout);
};
// Usage
async someFunction() {
const lineCount = await fileLineCount({ fileLocation: 'some/file.json' });
}