2013-11-20 2 views
89

Я ищу, чтобы обработать текстовый файл с узла с помощью вызова командной строки, как:Как читать из стандартного ввода построчно в Node

node app.js < input.txt

Каждая строка файла должна обрабатываться индивидуально , но после обработки входная строка может быть забыта.

Используя прослушиватель on-data для 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); 
}); 

Но это кажется таким неряшливым. Необходимо массировать первый и последний элементы массива линий. Нет ли более элегантного способа сделать это?

ответ

106

Вы можете использовать readline модуль для чтения из стандартного ввода построчно:

var readline = require('readline'); 
var rl = readline.createInterface({ 
    input: process.stdin, 
    output: process.stdout, 
    terminal: false 
}); 

rl.on('line', function(line){ 
    console.log(line); 
}) 
+2

Это, кажется, хорошо работать для ввода вход вручную в консоль, однако, когда я передаю файл в команду, файл отправляется на stdout. Жук? readline считается неустойчивой на данный момент. –

+1

Я думаю, что вы можете просто изменить 'process.stdout' на другой записываемый поток - это может быть так же просто, как' output: new require ('stream'). Writable() ' –

+3

К сожалению, мне нужен stdout. Я оставил его вне моего вопроса, но я пытаюсь заставить приложение использовать его как «node app.js < input.txt > output.txt'. –

35

readline разработан специально для работы с терминалом (то есть proccess.stdin.isTTY === true). Существует множество модулей, которые предоставляют функции разделения для общих потоков, например split. Это делает вещи супер-легкие:

process.stdin.pipe(require('split')()).on('data', processLine) 

function processLine (line) { 
    console.log(line + '!') 
} 
+1

«split» требуется для чтения из stdin? – Discordanian

+3

нет, это не так. Если вы не хотите читать строки за строкой, вам это совсем не нужно. – vkurchatkin

+2

Совет. Если вы хотите запустить код после обработки всех строк, добавьте '.on ('end', doMoreStuff)' after первый '.on()'. Помните, что если вы просто пишете код, как правило, после оператора с '.on()', этот код будет запускаться до чтения любого ввода, поскольку JavaScript не является синхронным. –

0

В моем случае программа (ELinks) вернулся линии, которые выглядели пустыми, но на самом деле имел специальные терминальные символы, управляющие цветовые коды и забой, поэтому 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) 
}) 
1

shareing для других:

читать поток построчно, должно быть хорошо для больших файлов конвейер на стандартный ввод, мой вариант:

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(); 
8
// Work on POSIX and Windows 
var stdinBuffer = fs.readFileSync(0); // STDIN_FILENO = 0 
console.log(stdinBuffer.toString()); 
+2

Не могли бы вы включить некоторые детали? Уже принят высокопринятый ответ – jhhoff02

+0

Это не работает для меня (узел v9.2.0, Windows). 'Ошибка: EISDIR: незаконная операция в каталоге, fstat в' tryStatSync (fs.js: 534: 13) ' – AlexChaffee

+0

Работал для меня на узле v6.11.2, OSX. – tiffon

Смежные вопросы