【问题标题】:readline doesn't stop line reading after rl.close() emit in nodejs在 nodejs 中发出 rl.close() 后,readline 不会停止行读取
【发布时间】:2017-10-24 12:18:43
【问题描述】:

我有以下文件,我想逐行读取并在找到“nameserver 8.8.8.8”后停止读取。

nameserver 8.8.8.8
nameserver 45.65.85.3
nameserver 40.98.3.3

我正在使用 nodejs 和 readline 模块来这样做

const readline = require('readline');
const fs = require('fs');

function check_resolv_nameserver(){
  // flag indicates whether namerserver_line was found or not
  var nameserver_flag = false;

  const rl = readline.createInterface({
    input: fs.createReadStream('file_to_read.conf')
  });

  rl.on('line', (line) => {
    console.log(`Line from file: ${line}`);
    if (line === 'nameserver 8.8.8.8'){
      console.log('Found the right file. Reading lines should stop here.');
      nameserver_flag = true;
      rl.close();
    }
  });

  rl.on('close', function(){
    if (nameserver_flag === true){
      console.log('Found nameserver 8.8.8.8');
    }
    else {
      console.log('Could not find nameserver 8.8.8.8');
    }
  });
}

check_resolv_nameserver();

由于我在阅读第一场比赛后立即使用 rl.close() 发出关闭事件,因此我希望我的代码仅读取第一行,然后停止进一步阅读。但是我的输出看起来像这样

Line from file: nameserver 8.8.8.8
Found the right file. Reading lines should stop here.
Found nameserver 8.8.8.8
Line from file: nameserver 45.65.85.3
Line from file: nameserver 40.98.3.3

如何让 readline 在第一次比赛后停止并让我继续做其他事情?

【问题讨论】:

  • 我的猜测是文件内容被缓冲了,所以如果缓冲区中还有完整的行,关闭rl(或文件句柄)不会阻止更多line事件被发出.一种解决方法是在获得正确的行后设置一个标志,如果设置了该标志,则忽略后续行。
  • @gvoigt : 你找到办法了吗
  • @robertklep,我认为您是对的...,因为数据大小实际上来自 createReadStream 的 highWaterMark...,只要有剩余的行,行事件就会一直触发。 ..
  • 要关闭rl我们必须先关闭readStream,但是readStrean一次读取的数据太多,我们无法停止。
  • lineReader.close(); lineReader.removeAllListeners()

标签: node.js readline


【解决方案1】:

对于那些无法让 linereader 停止的人,请执行以下操作(在您的 readline 回调中):

lineReader.close()
lineReader.removeAllListeners()

【讨论】:

    【解决方案2】:

    似乎 readline 缓冲了一些行,因此您必须添加自己的检查。

    例子:

    #! /usr/bin/node
    
    const fs = require('fs')
    const readline = require('readline')
    
    const reader = readline.createInterface({
        input: fs.createReadStream('test.js')
    })
    
    let wasRead = false
    
    reader.on('line', line => {
        if (wasRead) return undefined
        console.log('hello world')
        wasRead = true
        reader.close()
    })
    

    【讨论】:

      【解决方案3】:

      你也应该关闭流:

      const readline = require('readline');
      const fs = require('fs');
      const readStream = fs.createReadStream('file_to_read.conf');
      
      // More code here ...
      
      const rl = readline.createInterface({
          input: readStream
        });
      
      // Rest of your code
      
      rl.close();
      readStream.destroy();
      

      【讨论】:

      • 它不会真正起作用。请参阅上述答案中的 cmets,'line' 事件将继续触发,直到您通过缓冲区中的行(由 createReadStream 的 highWaterMark 指定的大小)...但是您 readStream.destroy() 应该停止任何新数据的到来在
      【解决方案4】:

      我搜索了很长时间我没有机会得到这个工作......所以我设法得到我想要的感谢节点模块:line-reader

      很好,因为它可以从文件中读取,也可以从缓冲区中读取。

      这是一个简单的代码示例,您可以在其中阅读 2 行然后停止。

      const lineReader = require('line-reader');
      const stream = require('stream');
      
      let bufferStream = new stream.PassThrough();
      bufferStream.end(yourBuffer);
      
      let lineNumber = 0;
      lineReader.eachLine(bufferStream, function(line) {
          lineNumber++;
          if (lineNumber === 1 || lineNumber === 2) {
              // Perform whatever
          } else {
      
              // returning false breaks the reading
              return false;
          }
      
      }, async function finished (err) {
          if (err) {
              // throw error or whatever
          }
      
          // Do after reading processing here
      });
      

      编辑:我找到了一种完全按计划实现一切的干净方法:

      第一次创建一个拆分器来读取字符串块

      class Splitter extends Transform {
          constructor(options){
              super(options);
              this.splitSize = options.splitSize;
              this.buffer = Buffer.alloc(0);
              this.continueThis = true;
          }
          stopIt() {
              this.continueThis = false;
          }
      
          _transform(chunk, encoding, cb){
      
              this.buffer = Buffer.concat([this.buffer, chunk]);
      
              while ((this.buffer.length > this.splitSize || this.buffer.length === 1) && this.continueThis){
                  try {
                      let chunk = this.buffer.slice(0, this.splitSize);
      
                      this.push(chunk);
                      this.buffer = this.buffer.slice(this.splitSize);
                      if (this.buffer[0] === 26){
                          console.log('EOF : ' + this.buffer[0]);
                      }
                  } catch (err) {
                      console.log('ERR OCCURED => ', err);
                      break;
                  }
              }
              console.log('WHILE FINISHED');
              cb();
          }
      }
      

      然后将其通过管道传输到您的流中:

      let bufferStream = new stream.PassThrough();
      bufferStream.end(hugeBuffer);
      let splitter = new Splitter({splitSize : 170}); // In my case I have 170 length lines, so I want to process them line by line
      let lineNr = 0;
      bufferStream
            .pipe(splitter)
            .on('data', async function(line){
      
                line = line.toString().trim();
      
                splitter.pause(); // pause stream so you can perform long time processing with await
                lineNr++;
      
               if (lineNr === 1){
                    // DO stuff with 1st line
      
               } else {
                    splitter.stopIt(); // Break the stream and stop reading so we just read 1st line
               }
      
               splitter.resume() // resumestream so you can process next chunk
          }).on('error', function(err){
                  console.log('Error while reading file.' + err);
                  // whatever
           }).on('end', async function(){
                 console.log('end event');
      
                 // Stream has ended, do whatever...
      
          });
      

      此代码可逐行实现完美的读取流。如果整个文件不是很长,则无需使用拆分器

      【讨论】:

        【解决方案5】:

        对我有用的是添加暂停简历,它允许我在阅读后编辑文件。

        var lineReader = require('readline').createInterface({
            input: require('fs').createReadStream(require('path').resolve('test.js'))
        });
        lineReader.on('line', function (line) { console.log(line) }) /*loop all lines*/
        .on('pause', function () { 
            /* resume after read lines is finished to close file */
            lineReader.resume(); 
        }) 
        .on('close', function () { 
            /*action after file read is close*/ 
            console.log('Close ok')
        }); 
        

        【讨论】:

          【解决方案6】:

          您可以声明一个线路事件侦听器并在需要时将其删除。

          const lineEventListener = (line) => {
            // do sth
            // Close
            rl.close();
            rl.removeListener('line', lineEventListener);
          }
          rl.on('line', lineEventListener);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-01-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-06-16
            相关资源
            最近更新 更多