Как читать из stdin строка за строкой в узле
Я ищу, чтобы обработать текстовый файл с узла с помощью командной строки типа:
node app.js < input.txt
каждая строка файла должна обрабатываться индивидуально, но после обработки входная строка может быть забыта.
используя прослушиватель данных stdin, я получаю входной пар, разделенный размером байта, поэтому я настраиваю это.
process.stdin.resume();
process.stdin.setEncoding('utf8');
var lingeringLine = "";
process.stdin.on('data', function(chunk) {
lines = chunk.split("n");
lines[0] = lingeringLine + lines[0];
lingeringLine = lines.pop();
lines.forEach(processLine);
});
process.stdin.on('end', function() {
processLine(lingeringLine);
});
но это кажется таким небрежным. Необходимость массировать вокруг первого и последнего элементов массива строк. Нет более элегантный способ сделать это?
6 ответов:
можно использовать readline модуль для чтения из stdin строка за строкой:
var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); rl.on('line', function(line){ console.log(line); })
readline
специально разработан для работы с терминалом (то естьproccess.stdin.isTTY === true
). Есть много модулей, которые обеспечивают функциональность разделения для общих потоков, таких как сплит. Это делает вещи супер-легко:process.stdin.pipe(require('split')()).on('data', processLine) function processLine (line) { console.log(line + '!') }
// Work on POSIX and Windows var stdinBuffer = fs.readFileSync(0); // STDIN_FILENO = 0 console.log(stdinBuffer.toString());
#!/usr/bin/env node const EventEmitter = require('events'); function stdinLineByLine() { const stdin = new EventEmitter(); let buff = ""; process.stdin .on('data', data => { buff += data; lines = buff.split(/[\r\n|\n]/); buff = lines.pop(); lines.forEach(line => stdin.emit('line', line)); }) .on('end', () => { if (buff.length > 0) stdin.emit('line', buff); }); return stdin; } const stdin = stdinLineByLine(); stdin.on('line', console.log);
в моем случае программа (elinks) возвращала строки, которые выглядели пустыми, но на самом деле имели специальные терминальные символы, коды управления цветом и backspace, поэтому
grep
варианты, представленные в других ответах, не работали для меня. Поэтому я написал этот небольшой скрипт в Node.js. Я вызвал файлtight
, но это просто случайное имя.#!/usr/bin/env node function visible(a) { var R = '' for (var i = 0; i < a.length; i++) { if (a[i] == '\b') { R -= 1; continue; } if (a[i] == '\u001b') { while (a[i] != 'm' && i < a.length) i++ if (a[i] == undefined) break } else R += a[i] } return R } function empty(a) { a = visible(a) for (var i = 0; i < a.length; i++) { if (a[i] != ' ') return false } return true } var readline = require('readline') var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }) rl.on('line', function(line) { if (!empty(line)) console.log(line) })
совместное использование для других:
читать поток строка за строкой, должно быть хорошо для больших файлов, передаваемых в stdin, моя версия:
var n=0; function on_line(line,cb) { ////one each line console.log(n++,"line ",line); return cb(); ////end of one each line } var fs = require('fs'); var readStream = fs.createReadStream('all_titles.txt'); //var readStream = process.stdin; readStream.pause(); readStream.setEncoding('utf8'); var buffer=[]; readStream.on('data', (chunk) => { const newlines=/[\r\n]+/; var lines=chunk.split(newlines) if(lines.length==1) { buffer.push(lines[0]); return; } buffer.push(lines[0]); var str=buffer.join(''); buffer.length=0; readStream.pause(); on_line(str,()=>{ var i=1,l=lines.length-1; i--; function while_next() { i++; if(i<l) { return on_line(lines[i],while_next); } else { buffer.push(lines.pop()); lines.length=0; return readStream.resume(); } } while_next(); }); }).on('end', ()=>{ if(buffer.length) var str=buffer.join(''); buffer.length=0; on_line(str,()=>{ ////after end console.error('done') ////end after end }); }); readStream.resume();