Ale*_*x C 517 javascript file-io lazy-evaluation node.js
我试图一次读一行大文件.我在Quora上发现了一个关于这个问题的问题,但是我错过了一些联系,以使整个事情融合在一起.
var Lazy=require("lazy");
new Lazy(process.stdin)
.lines
.forEach(
function(line) {
console.log(line.toString());
}
);
process.stdin.resume();
Run Code Online (Sandbox Code Playgroud)
我想弄清楚的是我如何从文件而不是STDIN一次读取一行,如本示例所示.
我试过了:
fs.open('./VeryBigFile.csv', 'r', '0666', Process);
function Process(err, fd) {
if (err) throw err;
// DO lazy read
}
Run Code Online (Sandbox Code Playgroud)
但它不起作用.我知道,在一个紧要关头,我可以回到使用像PHP这样的东西,但我想弄清楚这一点.
我认为其他答案不会起作用,因为文件比我正在运行它的服务器大得多.
Dan*_*scu 729
自Node.js v0.12和Node.js v4.0.0以来,有一个稳定的readline核心模块.这是从文件中读取行的最简单方法,没有任何外部模块:
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream('file.in')
});
lineReader.on('line', function (line) {
console.log('Line from file:', line);
});
Run Code Online (Sandbox Code Playgroud)
最后一行是正确读取的(从Node v0.12或更高版本开始),即使没有final \n.
更新:此示例已添加到Node的API官方文档中.
kof*_*asa 158
对于这样一个简单的操作,不应该依赖第三方模块.放轻松.
var fs = require('fs'),
readline = require('readline');
var rd = readline.createInterface({
input: fs.createReadStream('/path/to/file'),
output: process.stdout,
console: false
});
rd.on('line', function(line) {
console.log(line);
});
Run Code Online (Sandbox Code Playgroud)
Ray*_*nos 63
您不必拥有open该文件,而是必须创建一个ReadStream.
然后将该流传递给 Lazy
pol*_*tto 36
有一个非常好的模块用于逐行读取文件,它被称为行读取器
有了它,你只需写:
var lineReader = require('line-reader');
lineReader.eachLine('file.txt', function(line, last) {
console.log(line);
// do whatever you want with line...
if(last){
// or check if it's the last one
}
});
Run Code Online (Sandbox Code Playgroud)
如果需要更多控制,你甚至可以使用"java风格"界面迭代文件:
lineReader.open('file.txt', function(reader) {
if (reader.hasNextLine()) {
reader.nextLine(function(line) {
console.log(line);
});
}
});
Run Code Online (Sandbox Code Playgroud)
Joh*_*ams 33
require('fs').readFileSync('file.txt', 'utf-8').split(/\r?\n/).forEach(function(line){
console.log(line);
})
Run Code Online (Sandbox Code Playgroud)
nf0*_*590 19
老话题,但这有效:
var rl = readline.createInterface({
input : fs.createReadStream('/path/file.txt'),
output: process.stdout,
terminal: false
})
rl.on('line',function(line){
console.log(line) //or parse line
})
Run Code Online (Sandbox Code Playgroud)
简单.无需外部模块.
Ern*_*lli 18
您可以随时滚动自己的线路阅读器.我还没有对此片段进行基准测试,但它正确地将传入的块流分成不带尾随'\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();
Run Code Online (Sandbox Code Playgroud)
我在处理日志解析期间需要累积数据的快速日志解析脚本时确实想到了这一点,我觉得尝试使用js和节点而不是使用perl或bash这样做会很好.
无论如何,我确实认为小nodejs脚本应该是自包含的而不是依赖于第三方模块,所以在阅读了这个问题的所有答案后,每个人都使用各种模块来处理行解析,13 SLOC本机nodejs解决方案可能会引起关注.
Lea*_*per 16
2019年更新
一个很棒的示例已经发布在官方的Nodejs文档中。这里
这需要在您的计算机上安装最新的Node.js。> 11.4
const fs = require('fs');
const readline = require('readline');
async function processLineByLine() {
const fileStream = fs.createReadStream('input.txt');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
console.log(`Line from file: ${line}`);
}
}
processLineByLine();
Run Code Online (Sandbox Code Playgroud)
Lar*_*rry 13
Node.js v18.11.0 新增了逐行读取文件的功能
这就是您如何将其与您想要读取的文本文件一起使用
import { open } from 'node:fs/promises';
myFileReader();
async function myFileReader() {
const file = await open('./TextFileName.txt');
for await (const line of file.readLines()) {
console.log(line)
}
}
Run Code Online (Sandbox Code Playgroud)
要了解更多信息,请阅读 Node.js 文档,这里是文件系统 readlines() 的链接: https: //nodejs.org/api/fs.html#filehandlereadlinesoptions
Tou*_*ouv 12
使用运营商模块:
var carrier = require('carrier');
process.stdin.resume();
carrier.carry(process.stdin, function(line) {
console.log('got one line: ' + line);
});
Run Code Online (Sandbox Code Playgroud)
http结果是由于节点中的排放/暂停/恢复方式工作而使用Lazy逐行读取然后处理这些行并将它们写入另一个流时,最终导致了大量的大量内存泄漏(请参阅:http:// elegantcode .com/2011/04/06/take-baby-steps-with-node-js-pumping-data-between-streams /(我喜欢这个家伙顺便说一句)).我没有仔细查看Lazy究竟为什么要理解,但我无法暂停我的读取流以允许在没有Lazy退出的情况下消耗.
我编写了将大量csv文件处理成xml文档的代码,你可以在这里看到代码:https://github.com/j03m/node-csv2xml
如果您使用Lazy line运行以前的修订版,则会泄漏.最新版本根本没有泄漏,你可以将它作为阅读器/处理器的基础.虽然我有一些自定义的东西.
编辑:我想我还应该注意我的Lazy代码工作正常,直到我发现自己编写了足够大的xml片段,因为必要而耗尽/暂停/恢复.对于较小的块,它很好.
编辑:
使用转换流.
使用BufferedReader,您可以读取行.
new BufferedReader ("lorem ipsum", { encoding: "utf8" })
.on ("error", function (error){
console.log ("error: " + error);
})
.on ("line", function (line){
console.log ("line: " + line);
})
.on ("end", function (){
console.log ("EOF");
})
.read ();
Run Code Online (Sandbox Code Playgroud)
自从发布我的原始答案以来,我发现split是一个非常容易使用的节点模块,用于文件中的行读取; 其中也接受可选参数.
var split = require('split');
fs.createReadStream(file)
.pipe(split())
.on('data', function (line) {
//each chunk now is a seperate line!
});
Run Code Online (Sandbox Code Playgroud)
没有在非常大的文件上测试过.如果你这样做,请告诉我们.
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("++++++++++++++++++++")
})
Run Code Online (Sandbox Code Playgroud)
我想解决同样的问题,基本上在 Perl 中是这样的:
while (<>) {
process_line($_);
}
Run Code Online (Sandbox Code Playgroud)
我的用例只是一个独立的脚本,而不是服务器,所以同步很好。这些是我的标准:
这是一个让我感受 node.js 中的低级脚本类型代码并决定它作为其他脚本语言(如 Perl)替代品的可行性的项目。
经过惊人的努力和几次错误的启动,这是我想出的代码。它非常快,但比我预期的要简单:(在 GitHub 上分叉)
var fs = require('fs'),
StringDecoder = require('string_decoder').StringDecoder,
util = require('util');
function lineByLine(fd) {
var blob = '';
var blobStart = 0;
var blobEnd = 0;
var decoder = new StringDecoder('utf8');
var CHUNK_SIZE = 16384;
var chunk = new Buffer(CHUNK_SIZE);
var eolPos = -1;
var lastChunk = false;
var moreLines = true;
var readMore = true;
// each line
while (moreLines) {
readMore = true;
// append more chunks from the file onto the end of our blob of text until we have an EOL or EOF
while (readMore) {
// do we have a whole line? (with LF)
eolPos = blob.indexOf('\n', blobStart);
if (eolPos !== -1) {
blobEnd = eolPos;
readMore = false;
// do we have the last line? (no LF)
} else if (lastChunk) {
blobEnd = blob.length;
readMore = false;
// otherwise read more
} else {
var bytesRead = fs.readSync(fd, chunk, 0, CHUNK_SIZE, null);
lastChunk = bytesRead !== CHUNK_SIZE;
blob += decoder.write(chunk.slice(0, bytesRead));
}
}
if (blobStart < blob.length) {
processLine(blob.substring(blobStart, blobEnd + 1));
blobStart = blobEnd + 1;
if (blobStart >= CHUNK_SIZE) {
// blobStart is in characters, CHUNK_SIZE is in octets
var freeable = blobStart / CHUNK_SIZE;
// keep blob from growing indefinitely, not as deterministic as I'd like
blob = blob.substring(CHUNK_SIZE);
blobStart -= CHUNK_SIZE;
blobEnd -= CHUNK_SIZE;
}
} else {
moreLines = false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
它可能可以进一步清理,这是反复试验的结果。
在大多数情况下,这应该足够了:
const fs = require("fs")
fs.readFile('./file', 'utf-8', (err, file) => {
const lines = file.split('\n')
for (let line of lines)
console.log(line)
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
399098 次 |
| 最近记录: |