Node.js v12.4.0 文档


readline(逐行读取)#

中英对照提交修改

稳定性: 2 - 稳定

readline 模块提供了一个接口,用于一次一行地读取可读流(例如 process.stdin)中的数据。 它可以使用以下方式访问:

const readline = require('readline');

以下的简单示例说明了 readline 模块的基本用法。

const readline = require('readline');

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

rl.question('你如何看待 Node.js 中文网?', (answer) => {
  // TODO:将答案记录在数据库中。
  console.log(`感谢您的宝贵意见:${answer}`);

  rl.close();
});

一旦调用此代码,Node.js 应用程序将不会终止,直到 readline.Interface 关闭,因为接口在 input 流上等待接收数据。

Interface 类#

中英对照提交修改

readline.Interface 类的实例是使用 readline.createInterface() 方法构造的。 每个实例都关联一个 input 可读流和一个 output 可写流output 流用于为到达的用户输入打印提示,并从 input 流读取。

'close' 事件#

中英对照提交修改

当发生以下任一情况时会触发 'close' 事件:

  • 调用 rl.close() 方法,且 readline.Interface 实例放弃对 input 流和 output 流的控制;
  • input 流接收到其 'end' 事件;
  • input 流接收到 <ctrl>-D 以发信号传输结束(EOT);
  • input 流接收到 <ctrl>-C 以发信号 SIGINT,并且 readline.Interface 实例上没有注册 'SIGINT' 事件监听器。

调用监听器函数不传入任何参数。

一旦触发 'close' 事件,则 readline.Interface 实例就完成了。

'line' 事件#

中英对照提交修改

每当 input 流接收到行尾输入(\n\r\r\n)时就会触发 'line' 事件。 这种情况通常发生在当用户按下 <Enter> 键或 <Return> 键。

调用监听器函数时会带上包含接收到的那一行输入的字符串。

rl.on('line', (input) => {
  console.log(`接收到:${input}`);
});

'pause' 事件#

中英对照提交修改

当发生以下任一情况时会触发 'pause' 事件:

  • input 流被暂停。
  • input 流未暂停,且接收到 'SIGCONT' 事件。(参阅 'SIGTSTP' 事件和 'SIGCONT' 事件)

调用监听器函数时不传入任何参数。

rl.on('pause', () => {
  console.log('Readline 暂停');
});

'resume' 事件#

中英对照提交修改

每当 input 流恢复时,就会触发 'resume' 事件。

调用监听器函数时不传入任何参数。

rl.on('resume', () => {
  console.log('Readline 恢复');
});

'SIGCONT' 事件#

中英对照提交修改

当先前使用 <ctrl>-Z(即 SIGTSTP)移入后台的 Node.js 进程使用 fg(1p) 返回到前台时,就会触发 'SIGCONT' 事件。

如果 input 流在 SIGTSTP 请求之前被暂停,则不会触发此事件。

调用监听器函数时不传入任何参数。

rl.on('SIGCONT', () => {
  // `prompt` 将自动恢复流。
  rl.prompt();
});

Windows 上不支持 'SIGCONT' 事件。

'SIGINT' 事件#

中英对照提交修改

每当 input 流接收到 <ctrl>-C 输入(通常称为 SIGINT)时,就会触发 'SIGINT' 事件。 如果当 input 流接收到 SIGINT 时没有注册 'SIGINT' 事件监听器,则会触发 'pause' 事件。

调用监听器函数时不传入任何参数。

rl.on('SIGINT', () => {
  rl.question('确定要退出吗?', (answer) => {
    if (answer.match(/^y(es)?$/i)) rl.pause();
  });
});

'SIGTSTP' 事件#

中英对照提交修改

每当 input 流接收到 <ctrl>-Z 输入(通常称为 SIGTSTP)时,就会触发 'SIGTSTP' 事件。 如果当 input 流接收到 SIGTSTP 时没有注册 'SIGTSTP' 事件监听器,则 Node.js 进程将被发送到后台。

当使用 fg(1p) 恢复程序时,将触发 'pause''SIGCONT' 事件。 这可用于恢复 input 流。

如果在将进程发送到后台之前暂停 input,则不会触发 'pause''SIGCONT' 事件。

调用监听器函数时不传入任何参数。

rl.on('SIGTSTP', () => {
  // 这将覆盖 SIGTSTP 并阻止程序进入后台。
  console.log('捕获 SIGTSTP');
});

Windows 上不支持 'SIGTSTP' 事件。

rl.close()#

中英对照提交修改

rl.close() 方法会关闭 readline.Interface 实例,并放弃对 inputoutput 流的控制。 当调用时,将触发 'close' 事件。

调用 rl.close() 不会立即停止 readline.Interface 实例触发的其他事件(包括 'line')。

rl.pause()#

中英对照提交修改

rl.pause() 方法会暂停 input 流,允许稍后在必要时恢复它。

调用 rl.pause() 不会立刻暂停 readline.Interface 实例触发的其他事件(包括 'line')。

rl.prompt([preserveCursor])#

中英对照提交修改

  • preserveCursor <boolean> 如果为 true,则阻止将光标落点重置为 0

rl.prompt() 方法将 readline.Interface 实例配置的提示写入 output 中的新一行,以便为用户提供一个可供输入的新位置。

当调用时,如果 input 流已暂停,则 rl.prompt() 将恢复它。

如果 readline.Interface 创建时 output 被设置为 nullundefined,则不会写入提示。

rl.question(query, callback)#

中英对照提交修改

  • query <string> 要写入 output 的语句或询问,前置于提示符。
  • callback <Function> 回调函数,调用时传入用户的输入以响应 query

rl.question() 方法通过将 query 写入 output 来显示它,并等待用户在 input 上提供输入,然后调用 callback 函数将提供的输入作为第一个参数传入。

当调用时,如果 input 流已暂停,则 rl.question() 将恢复 input 流。

如果 readline.Interface 创建时 output 被设置为 nullundefined,则不会写入 query

用法示例:

rl.question('你最喜欢的食物是什么?', (answer) => {
  console.log(`你最喜欢的食物是 ${answer}`);
});

传给 rl.question()callback 函数不遵循接受 Error 对象或 null 作为第一个参数的经典模式。 调用 callback 时使用提供的答案作为唯一的参数。

rl.resume()#

中英对照提交修改

如果 input 流已暂停,则 rl.resume() 方法将恢复它。

rl.setPrompt(prompt)#

中英对照提交修改

rl.setPrompt() 方法设置每当调用 rl.prompt() 时将写入 output 的提示。

rl.write(data[, key])#

中英对照提交修改

rl.write() 方法将 datakey 标识的按键序列写入 output。 仅当 outputTTY 文本终端时才支持 key 参数。

如果指定了 key,则忽略 data

当调用时,如果 input 流已暂停,则 rl.write() 将恢复它。

如果 readline.Interface 创建时 output 被设置为 nullundefined,则不会写入 datakey

rl.write('删除这个!');
// 模拟 Ctrl+u 删除先前写入的行。
rl.write(null, { ctrl: true, name: 'u' });

rl.write() 方法将数据写入 readlineInterfaceinput,就像它是由用户提供的一样。

rl[Symbol.asyncIterator]()#

暂无中英对照

Stability: 2 - Stable

Create an AsyncIterator object that iterates through each line in the input stream as a string. This method allows asynchronous iteration of readline.Interface objects through for-await-of loops.

Errors in the input stream are not forwarded.

If the loop is terminated with break, throw, or return, rl.close() will be called. In other words, iterating over a readline.Interface will always consume the input stream fully.

A caveat with using this experimental API is that the performance is currently not on par with the traditional 'line' event API, and thus it is not recommended for performance-sensitive applications. We expect this situation to improve in the future.

async function processLineByLine() {
  const rl = readline.createInterface({
    // ...
  });

  for await (const line of rl) {
    // Each line in the readline input will be successively available here as
    // `line`.
  }
}

readline.clearLine(stream, dir)#

中英对照提交修改

readline.clearLine() 方法在由 dir 标识的指定方向上清除给定的 TTY 流的当前行。

readline.clearScreenDown(stream)#

中英对照提交修改

readline.clearScreenDown() 方法从光标的当前位置向下清除给定的 TTY 流。

readline.createInterface(options)#

中英对照提交修改

  • options <Object>

    • input <stream.Readable> 要监听的可读流。此选项是必需的。
    • output <stream.Writable> 将逐行读取数据写入的可写流
    • completer <Function> 用于 Tab 自动补全的可选函数。
    • terminal <boolean> 如果 inputoutput 应该被视为 TTY,并且写入 ANSI/VT100 转义码,则为 true默认值: 实例化时在 output 流上检查 isTTY
    • historySize <number> 保留的最大历史记录行数。 要禁用历史记录,请将此值设置为 0。 仅当用户或内部 output 检查将 terminal 设置为 true 时,此选项才有意义,否则根本不会初始化历史记录缓存机制。 默认值: 30
    • prompt - 要使用的提示字符串。默认值: '> '
    • crlfDelay <number> 如果 \r\n 之间的延迟超过 crlfDelay 毫秒,则 \r\n 将被视为单独的行尾输入。 crlfDelay 将被强制转换为不小于 100 的数字。 可以设置为 Infinity, 这种情况下, \r 后跟 \n 将始终被视为单个换行符(对于使用 \r\n 行分隔符的文件读取可能是合理的)。 默认值: 100
    • removeHistoryDuplicates <boolean> 如果为 true, 则当添加到历史列表的新输入行与旧的输入行重复时,将从列表中删除旧行。 默认值: false

readline.createInterface() 方法创建一个新的 readline.Interface 实例。

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

一旦创建了 readline.Interface 实例,最常见的用例是监听 'line' 事件:

rl.on('line', (line) => {
  console.log(`接收到:${line}`);
});

如果此实例的 terminaltrue,则若它定义了一个 output.columns 属性则 output 流会获得最佳兼容性,并且如果或当列发生变化时, output 上会触发 'resize' 事件(当它是 TTY 时,process.stdout 会自动执行此操作)。

completer 函数的使用#

查看v10.x中文文档

The completer function takes the current line entered by the user as an argument, and returns an Array with 2 entries:

  • An Array with matching entries for the completion.
  • The substring that was used for the matching.

For instance: [[substr1, substr2, ...], originalsubstring].

function completer(line) {
  const completions = '.help .error .exit .quit .q'.split(' ');
  const hits = completions.filter((c) => c.startsWith(line));
  // Show all completions if none found
  return [hits.length ? hits : completions, line];
}

The completer function can be called asynchronously if it accepts two arguments:

function completer(linePartial, callback) {
  callback(null, [['123'], linePartial]);
}

readline.cursorTo(stream, x, y)#

中英对照提交修改

readline.cursorTo() 方法将光标移动到给定的 TTY stream 中的指定位置。

readline.emitKeypressEvents(stream[, interface])#

中英对照提交修改

readline.emitKeypressEvents() 方法使给定的可读流开始触发与接收的输入相对应的 'keypress' 事件。

可选的 interface 指定 readline.Interface 实例,当检测到复制粘贴输入时,将禁用自动补全。

如果 streamTTY,则它必须处于原始模式。

如果 input 是终端,则由其 input 上的任何 readline 实例自动调用。 关闭 readline 实例不会阻止 input 触发 'keypress' 事件。

readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY)
  process.stdin.setRawMode(true);

readline.moveCursor(stream, dx, dy)#

中英对照提交修改

readline.moveCursor() 方法相对于给定的 TTY stream 中的当前位置移动光标。

示例:微型 CLI#

中英对照提交修改

以下示例说明了如何使用 readline.Interface 类来实现一个小型命令行界面:

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  prompt: '请输入> '
});

rl.prompt();

rl.on('line', (line) => {
  switch (line.trim()) {
    case 'hello':
      console.log('world!');
      break;
    default:
      console.log(`你输入的是:'${line.trim()}'`);
      break;
  }
  rl.prompt();
}).on('close', () => {
  console.log('再见!');
  process.exit(0);
});

示例:逐行读取文件流#

中英对照提交修改

readline 的一个常见用例是每次一行地从文件系统可读流消费输入:

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

const rl = readline.createInterface({
  input: fs.createReadStream('sample.txt'),
  crlfDelay: Infinity
});

rl.on('line', (line) => {
  console.log(`文件的每行内容:${line}`);
});