programing

노드에서 stdin에서 한 줄씩 읽는 방법

i4 2023. 5. 11. 21:06
반응형

노드에서 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);
});

하지만 이건 너무 엉성해 보여요.라인 배열의 첫 번째와 마지막 항목을 마사지해야 합니다.이보다 더 우아한 방법은 없을까요?

읽기 라인 모듈을 사용하여 stdin에서 한 줄씩 읽을 수 있습니다.

const readline = require('readline');

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

rl.on('line', (line) => {
    console.log(line);
});

rl.once('close', () => {
     // end of input
 });
// Work on POSIX and Windows
var fs = require("fs");
var stdinBuffer = fs.readFileSync(0); // STDIN_FILENO = 0
console.log(stdinBuffer.toString());

readline단말기(즉, 즉process.stdin.isTTY === true). 스플릿과 같은 일반 스트림에 대한 스플릿 기능을 제공하는 많은 모듈이 있습니다.이를 통해 매우 간편하게 작업할 수 있습니다.

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

function processLine (line) {
  console.log(line + '!')
}
#!/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);

오래된 질문에 대한 새로운 대답.

노드 10(2018년 4월) 이후로 프로세스.stdin과 같은 읽기 가능한 스트림은 추가 덕분에 대기 루프를 지원합니다.Symbol.asyncIterator메서드(ReadableStream 설명서, Symbol.asyncIter 설명서).

이것을 사용하여 우리는 데이터 덩어리를 통해 반복하는 것에서 라인을 통해 반복하는 어댑터를 만들 수 있습니다.이를 위한 논리는 이 답변에서 수정되었습니다.

function streamByLines(stream) {
  stream.setEncoding('utf8');
  return {
    async *[Symbol.asyncIterator]() {
      let buffer = '';

      for await (const chunk of stream) {
        buffer += chunk;
        const lines = buffer.split(/\r?\n/);
        buffer = lines.pop();
        for (const line of lines) {
          yield line;
        }
      }
      if (buffer.length > 0) yield buffer;
    },
  };
}

대기가 허용되는 컨텍스트에서 이렇게 사용할 수 있습니다.

for await (const line of streamByLines(process.stdin)) {
  console.log('Current line:', line)
}

스트림을 한 줄씩 읽습니다. stdin, my version에 연결된 대용량 파일에 적합합니다.

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();

설명:

  • 중간 바이트 집합 인코딩에서 utf8이 아닌 utf8 문자에서 정확하게 잘라내기 위해 전체 멀티바이트 문자를 보낼 때마다 해당 문자를 내보냅니다.
  • 데이터가 수신되면 입력이 일시 중지됩니다.모든 라인이 사용될 때까지 입력을 차단하는 데 사용됩니다.라인 처리 기능이 입력보다 느릴 경우 뷔페가 넘쳐나는 것을 방지합니다.
  • 매번 새 줄이 없는 줄이 있는 경우.모든 호출에 대해 이 값을 계산하고 아무것도 하지 않아야 합니다. 한 번 더 많은 회선이 있으면 이 값을 추가하고 계산된 버퍼를 사용합니다.
  • 모든 분할된 라인이 소비된 후에.마지막 줄에서 마지막 줄을 눌러 버퍼링하고 일시 중지된 스트림을 다시 시작합니다.

es6 코드

var n=0;
async function on_line(line)
{
    ////one each line
    console.log(n++,"line ",line);
    ////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', async (chunk) => {
    
    const newlines=/[\r\n]+/;
    var lines=chunk.split(newlines)
    if(lines.length==1)
    {
        buffer.push(lines[0]);
        return;
    }
    readStream.pause();

    // let i=0;
    buffer.push(lines[0]); // take first line
    var str=buffer.join('');
    buffer.length=0;//clear array, because consumed
    await on_line(str);
    
    for(let i=1;i<lines.length-1;i++)
       await on_line(lines[i]);
    buffer.push(lines[lines.length-1]);
    lines.length=0; //optional, clear array to hint GC.
    return readStream.resume();
  }).on('end', async ()=>{
      if(buffer.length)
          var str=buffer.join('');
          buffer.length=0;
          await on_line(str);
  });
  readStream.resume();

나는 es6 코드를 테스트하지 않았습니다.

나의 경우, 프로그램(링크)은 빈 것처럼 보이는 행을 반환했지만, 사실 특별한 터미널 문자, 색 제어 코드 및 백스페이스를 가지고 있었습니다.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) 
})

사용자에게 먼저 줄 수를 묻으려면 다음을 수행합니다.

    //array to save line by line 
    let xInputs = [];

    const getInput = async (resolve)=>{
            const readline = require('readline').createInterface({
                input: process.stdin,
                output: process.stdout,
            });
            readline.on('line',(line)=>{
            readline.close();
            xInputs.push(line);
            resolve(line);
            })
    }

    const getMultiInput = (numberOfInputLines,callback)=>{
        let i = 0;
        let p = Promise.resolve(); 
        for (; i < numberOfInputLines; i++) {
            p = p.then(_ => new Promise(resolve => getInput(resolve)));
        }
        p.then(()=>{
            callback();
        });
    }

    //get number of lines 
    const readline = require('readline').createInterface({
        input: process.stdin,
        output: process.stdout,
        terminal: false
    });
    readline.on('line',(line)=>{
        getMultiInput(line,()=>{
           //get here the inputs from xinputs array 
        });
        readline.close();
    })

process.stdin.pipe(process.stdout);

언급URL : https://stackoverflow.com/questions/20086849/how-to-read-from-stdin-line-by-line-in-node

반응형