- 断言测试
- 异步上下文跟踪
- 异步钩子
- 缓冲(Buffer)
- C++ 插件
- 使用 Node-API 的 C/C++ 插件
- C++ 嵌入 Node环境
- 子进程(Child processes)
- 集群(Cluster)
- 命令行选项
- 控制台(Console)
- 核心包(Corepack)
- 加密(Crypto)
- 调试器(Debugger)
- 已弃用的 API
- 诊断通道(Diagnostics Channel)
- 域名系统(DNS)
- 域(Domain)
- 错误(Errors)
- 事件(Events)
- 文件系统(File system)
- 全局变量(Globals)
- HTTP
- HTTP/2
- HTTPS
- 检查器(Inspector)
- 国际化
- 模块:CommonJS 模块
- 模块:ECMAScript 模块
- 模块:
node:module
API - 模块:packages 模块
- 网络(Net)
- 系统(OS)
- 路径(Path)
- 性能挂钩(Performance hooks)
- 性能挂钩(Permissions)
- 进程(Process)
- Punycode 国际化域名编码
- 查询字符串(Query strings)
- 命令行库(Readline)
- REPL 交互式编程环境
- 诊断报告
- 单个可执行应用程序
- Stream 流
- 字符串解码器
- 单元测试
- 定时器(Timers)
- 传输层安全/SSL
- 跟踪事件
- TTY
- UDP/数据报
- URL
- 实用程序
- V8
- 虚拟机
- WebAssembly
- Web加密 API(Web Crypto API)
- 网络流 API(Web Streams API)
- 工作线程(Worker threads)
- zlib
Node.js v18.18.2 文档
- Node.js v18.18.2
-
►
目录
- Readline
- Class:
InterfaceConstructor
- Event:
'close'
- Event:
'line'
- Event:
'history'
- Event:
'pause'
- Event:
'resume'
- Event:
'SIGCONT'
- Event:
'SIGINT'
- Event:
'SIGTSTP'
rl.close()
rl.pause()
rl.prompt([preserveCursor])
rl.question(query[, options], callback)
rl.resume()
rl.setPrompt(prompt)
rl.getPrompt()
rl.write(data[, key])
rl[Symbol.asyncIterator]()
rl.line
rl.cursor
rl.getCursorPos()
- Event:
- Promises API
- Callback API
readline.emitKeypressEvents(stream[, interface])
- Example: Tiny CLI
- Example: Read file stream line-by-Line
- TTY keybindings
- Class:
- Readline
-
►
索引
- Assertion testing
- Asynchronous context tracking
- Async hooks
- Buffer
- C++ addons
- C/C++ addons with Node-API
- C++ embedder API
- Child processes
- Cluster
- Command-line options
- Console
- Corepack
- Crypto
- Debugger
- Deprecated APIs
- Diagnostics Channel
- DNS
- Domain
- Errors
- Events
- File system
- Globals
- HTTP
- HTTP/2
- HTTPS
- Inspector
- Internationalization
- Modules: CommonJS modules
- Modules: ECMAScript modules
- Modules:
node:module
API - Modules: Packages
- Net
- 系统(OS)
- 路径(Path)
- Performance hooks
- Permissions
- 进程(Process)
- Punycode
- Query strings
- 命令行库(Readline)
- REPL 交互式编程环境
- Report
- Single executable applications
- Stream
- String decoder
- Test runner
- Timers
- TLS/SSL
- Trace events
- TTY
- UDP/datagram
- URL
- Utilities
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- Worker threads
- Zlib
- ► 其他版本
- ► 选项
目录
- Readline
- 类:
InterfaceConstructor
- 事件:
'close'
- 事件:
'line'
- 事件:
'history'
- 事件:
'pause'
- 事件:
'resume'
- 事件:
'SIGCONT'
- 事件:
'SIGINT'
- 事件:
'SIGTSTP'
rl.close()
rl.pause()
rl.prompt([preserveCursor])
rl.question(query[, options], callback)
rl.resume()
rl.setPrompt(prompt)
rl.getPrompt()
rl.write(data[, key])
rl[Symbol.asyncIterator]()
rl.line
rl.cursor
rl.getCursorPos()
- 事件:
- Promise API
- 回调接口
readline.emitKeypressEvents(stream[, interface])
- 示例:微型 CLI
- 示例:逐行读取文件流
- TTY 键绑定
- 类:
Readline#
源代码: lib/readline.js
node:readline
模块提供了一个接口,用于从可读流(例如process.stdin
)中一次读取一行数据
。
要使用基于 Promise 的 API:
import * as readline from 'node:readline/promises';
const readline = require('node:readline/promises');
要使用回调和同步 API:
import * as readline from 'node:readline';
const readline = require('node:readline');
以下简单示例说明了node:readline
模块的基本用法。
import * as readline from 'node:readline/promises';
import { stdin as input, stdout as output } from 'node:process';
const rl = readline.createInterface({ input, output });
const answer = await rl.question('What do you think of Node.js? ');
console.log(`Thank you for your valuable feedback: ${answer}`);
rl.close();
const readline = require('node:readline');
const { stdin: input, stdout: output } = require('node:process');
const rl = readline.createInterface({ input, output });
rl.question('What do you think of Node.js? ', (answer) => {
// TODO: Log the answer in a database
console.log(`Thank you for your valuable feedback: ${answer}`);
rl.close();
});
一旦调用此代码,Node.js 应用程序将不会终止,直到
readline.Interface
关闭,因为接口等待在input
流上接收数据。
类:InterfaceConstructor
#
InterfaceConstructor
类的实例是使用
readlinePromises.createInterface()
或readline.createInterface()
方法构造的。每个实例都与一个input
可读流和一个output
可写流关联。output
流用于打印到达input
流并从中读取的用户输入的提示。
事件:'close'
#
当发生以下情况之一时,会发出'close'
事件:
- 调用
rl.close()
方法,并且InterfaceConstructor
实例放弃对input
和output
流的控制; input
流接收其'end'
事件;input
流接收Ctrl+D来表示传输结束 (EOT);input
流接收Ctrl+C来发出SIGINT
信号,并且'SIGINT'
实例上 没有注册'SIGINT'
事件侦听器。
调用侦听器函数时不传递任何参数。
一旦发出'close'
事件,InterfaceConstructor
实例就会完成。
事件:'line'
#
每当input
流收到行尾输入(\n
、\r
或\r\n
)。当用户按Enter或 时,通常会发生这种情况Return。
如果从流中读取了新数据并且该流在没有最终行尾标记的情况下结束,也会发出'line'
事件。
使用包含单行接收输入的字符串调用侦听器函数。
rl.on('line', (input) => {
console.log(`Received: ${input}`);
});
事件:'history'
#
每当历史数组发生更改时,就会发出'history'
事件。
使用包含历史数组的数组调用侦听器函数。它将反映由于
historySize
和removeHistoryDuplicates
引起的所有更改、添加的行和删除的行。
主要目的是让侦听器保留历史记录。侦听器也可以更改历史对象。这对于防止将某些行添加到历史记录中很有用,例如密码。
rl.on('history', (history) => {
console.log(`Received: ${history}`);
});
事件:'pause'
#
当发生以下情况之一时,会发出'pause'
事件:
调用侦听器函数时不传递任何参数。
rl.on('pause', () => {
console.log('Readline paused.');
});
事件:'resume'
#
每当input
流恢复时,就会发出 'resume'
事件。
调用侦听器函数时不传递任何参数。
rl.on('resume', () => {
console.log('Readline resumed.');
});
事件:'SIGCONT'
#
当之前使用+ (即SIGTSTP
)移至后台的 Node.js 进程随后使用fg(1p)
返回前台时,会发出 'SIGCONT'
事件。CtrlZ
如果input
流在SIGTSTP
请求之前暂停,则不会发出此事件。
调用侦听器函数时无需传递任何参数。
rl.on('SIGCONT', () => {
// `prompt` will automatically resume the stream
rl.prompt();
});
Windows 不支持{ { {0141}}}事件。
事件:'SIGINT'
#
每当 input
流收到Ctrl+C输入(通常称为SIGINT
)时,就会发出 'SIGINT'
事件。如果当input
流接收到
SIGINT
时没有
注册'SIGINT'
事件侦听器,则将发出'pause'
事件。
调用侦听器函数时无需传递任何参数。
rl.on('SIGINT', () => {
rl.question('Are you sure you want to exit? ', (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', () => {
// This will override SIGTSTP and prevent the program from going to the
// background.
console.log('Caught SIGTSTP.');
});
Windows 不支持{ { {0164}}}事件。
rl.close()
#
rl.close()
方法关闭InterfaceConstructor
实例并放弃对input
和output
流的控制。调用时,将发出'close'
事件。
调用rl.close()
不会立即阻止 InterfaceConstructor
实例发出其他事件(包括'line'
)。
rl.pause()
#
rl.pause()
方法暂停input
流,以便稍后在必要时恢复。
调用rl.pause()
不会立即暂停 InterfaceConstructor
实例发出的其他事件(包括'line'
)。
rl.prompt([preserveCursor])
#
preserveCursor
<boolean>如果为true
,则防止光标位置重置为0
。
rl.prompt()
方法将配置为prompt
的InterfaceConstructor
实例写入
output
中的新行,以便为用户提供位于以下位置的新位置提供输入。
调用时,rl.prompt()
将恢复已暂停的input
流。
如果创建InterfaceConstructor
时将output
设置为null
或
undefined
,则不会写入提示。
rl.question(query[, options], callback)
#
query
<string>要写入output
的语句或查询,放在提示符前面。options
<对象>signal
<AbortSignal>(可选)允许使用AbortController
取消question()
。
callback
<Function>使用用户输入调用的回调函数,以响应query
。
rl.question()
方法通过将其写入output
来显示query
,等待在input
上提供用户输入,然后调用callback
函数将提供的输入作为第一个参数传递。
调用时,rl.question()
将恢复已暂停的input
流。
如果创建InterfaceConstructor
时将output
设置为null
或
undefined
,则不会写入query
。
传递给rl.question()
的callback
函数不遵循接受Error
对象或null
作为第一个参数的典型模式。使用提供的答案作为唯一参数来调用callback
。
如果在 rl.close()
之后调用rl.question()
将会抛出错误。
用法示例:
rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
使用AbortController
取消问题。
const ac = new AbortController();
const signal = ac.signal;
rl.question('What is your favorite food? ', { signal }, (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
setTimeout(() => ac.abort(), 10000);
rl.resume()
#
如果input
流已暂停,则rl.resume()
方法会恢复该流。
rl.setPrompt(prompt)
#
prompt
<字符串>
rl.setPrompt()
方法设置每当调用rl.prompt()
时将写入 output
的提示。
rl.getPrompt()
#
- 返回:<string>当前提示字符串
rl.getPrompt()
方法返回rl.prompt()
使用的当前提示。
rl.write(data[, key])
#
rl.write()
方法会将data
或由key
标识的按键序列写入output
。仅当output
是TTY文本终端时才支持 key
参数。有关组合键列表,请参阅TTY 键绑定。
如果指定了key
,则忽略data
。
调用时,rl.write()
将恢复已暂停的input
流。
如果创建InterfaceConstructor
时将output
设置为null
或
undefined
,则data
和key
没有写。
rl.write('Delete this!');
// Simulate Ctrl+U to delete the line written previously
rl.write(null, { ctrl: true, name: 'u' });
rl.write()
方法会将数据写入readline
Interface
的
input
,就好像数据是由用户提供的一样。
rl[Symbol.asyncIterator]()
#
- 返回:<异步迭代器>
创建一个AsyncIterator
对象,该对象将输入流中的每一行作为字符串进行迭代。此方法允许通过for await...of
循环异步迭代
InterfaceConstructor
对象。
输入流中的错误不会被转发。
如果循环以break
、throw
或return
终止,
则将调用rl.close()
。换句话说,迭代
InterfaceConstructor
将始终完全消耗输入流。
性能与传统的'line'
事件 API不相上下。
对于性能敏感的应用程序,请使用'line'
。
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.createInterface()
将开始消耗输入流。在界面创建和异步迭代之间进行异步操作可能会导致漏行。
rl.line
#
节点正在处理的当前输入数据。
在从 TTY 流收集输入以检索在发出line
事件之前迄今为止已处理的当前值时,可以使用此方法。一旦发出line
事件,此属性将是一个空字符串。
请注意,如果不控制rl.cursor
,则在实例运行时修改该值可能会产生意想不到的后果。
如果不使用 TTY 流进行输入,请使用'line'
事件。
一种可能的用例如下:
const values = ['lorem ipsum', 'dolor sit amet'];
const rl = readline.createInterface(process.stdin);
const showResults = debounce(() => {
console.log(
'\n',
values.filter((val) => val.startsWith(rl.line)).join(' '),
);
}, 300);
process.stdin.on('keypress', (c, k) => {
showResults();
});
rl.cursor
#
相对于rl.line
的光标位置。
当从 TTY 流读取输入时,这将跟踪当前光标在输入字符串中的位置。光标的位置决定了处理输入时将修改的输入字符串部分,以及将呈现终端插入符的列。
rl.getCursorPos()
#
返回光标相对于输入提示+字符串的实际位置。长输入(换行)字符串以及多行提示都包含在计算中。
Promise API#
类:readlinePromises.Interface
#
readlinePromises.Interface
类的实例是使用
readlinePromises.createInterface()
方法构造的。每个实例都与单个input
可读流和单个output
可写流关联。output
流用于打印到达input
流并从中读取的用户输入的提示。
rl.question(query[, options])
#
query
<string>要写入output
的语句或查询,放在提示符前面。options
<对象>signal
<AbortSignal>(可选)允许使用AbortSignal
取消question()
。
- 返回:<Promise>通过用户响应
query
的输入来履行的 Promise 。
rl.question()
方法通过将query
写入output
来显示 query
,等待在input
上提供用户输入,然后调用callback
函数将提供的输入作为第一个参数传递。
调用时,rl.question()
将恢复已暂停的input
流。
如果创建readlinePromises.Interface
时将output
设置为null
或
undefined
,则不会写入query
。
如果在rl.close()
之后调用问题,它将返回拒绝的 Promise 。
用法示例:
const answer = await rl.question('What is your favorite food? ');
console.log(`Oh, so your favorite food is ${answer}`);
使用AbortSignal
取消问题。
const signal = AbortSignal.timeout(10_000);
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
const answer = await rl.question('What is your favorite food? ', { signal });
console.log(`Oh, so your favorite food is ${answer}`);
类:readlinePromises.Readline
#
new readlinePromises.Readline(stream[, options])
#
stream
< stream.Writable> TTY流。options
<对象>autoCommit
<boolean>如果true
,则无需调用rl.commit()
。
rl.clearLine(dir)
#
dir
<整数>-1
:光标左侧1
:光标右侧0
:整行
- 返回:这个
rl.clearLine()
方法将一个操作添加到待处理操作的内部列表中,该操作会按照dir
标识的指定方向清除关联的 stream
的当前行。调用rl.commit()
以查看此方法的效果,除非autoCommit: true
已传递给构造函数。
rl.clearScreenDown()
#
- 返回:这个
rl.clearScreenDown()
方法向待处理操作的内部列表添加一个从光标当前位置向下清除关联流的操作。调用rl.commit()
以查看此方法的效果,除非autoCommit: true
已传递给构造函数。
rl.commit()
#
- 返回:< Promise >
rl.commit()
方法将所有待处理操作发送到关联的
stream
并清除待处理操作的内部列表。
rl.cursorTo(x[, y])
#
rl.cursorTo()
方法将一个操作添加到待处理操作的内部列表中,该操作将光标移动到关联的stream
中的指定位置。调用rl.commit()
以查看此方法的效果,除非autoCommit: true
已传递给构造函数。
rl.moveCursor(dx, dy)
#
rl.moveCursor()
方法将一个操作添加到待处理操作的内部列表中,该操作将光标相对于关联的stream
中的当前位置移动。调用rl.commit()
以查看此方法的效果,除非autoCommit: true
已传递给构造函数。
rl.rollback()
#
- 返回:这个
rl.rollback
方法会清除待处理操作的内部列表,而不将其发送到关联的stream
。
readlinePromises.createInterface(options)
#
options
<对象>input
<stream.Readable>要侦听的可读流。该选项是必需的。output
<stream.Writable>用于写入读取行数据的可写流。completer
<Function>用于 Tab 自动补全的可选函数。terminal
<boolean>true
是否应将input
和output
流视为 TTY,并写入 ANSI/VT100 转义码到它。 默认值:实例化时检查output
流上的isTTY
。history
<string[]>历史行的初始列表。仅当用户或内部output
检查将terminal
设置为true
时,此选项才有意义 ,否则历史记录缓存机制根本不会初始化。 默认值:[]
。historySize
<number>保留的历史记录行的最大数量。要禁用历史记录,请将此值设置为0
。仅当用户或内部output
检查将terminal
设置为true
时,此选项才有意义 ,否则历史记录缓存机制根本不会初始化。 默认值:30
。removeHistoryDuplicates
<boolean>如果为true
,则当添加到历史记录列表中的新输入行与旧输入行重复时,将从列表中删除旧行。默认值:false
。prompt
<string>要使用的提示字符串。默认值:'> '
。crlfDelay
<number>如果\r
和\n
之间的延迟超过crlfDelay
毫秒,则\r
和\n
将被视为单独的行尾输入。crlfDelay
将被强制为不小于100
的数字 。它可以设置为Infinity
,在这种情况下\r
后跟\n
将始终被视为单个换行符(这对于 使用{ { {0394}}}行分隔符)。默认值:100
。escapeCodeTimeout
<number>持续时间readlinePromises
将等待一个字符(当以毫秒为单位读取不明确的按键序列时,该字符既可以使用到目前为止读取的输入形成完整的按键序列,也可以需要额外的输入来完成更长的按键序列)。 默认值:500
。tabSize
<整数>制表符等于的空格数(最小 1)。 默认值:8
。
- 返回:<readlinePromises.Interface>
readlinePromises.createInterface()
方法创建一个新的readlinePromises.Interface
实例。
const readlinePromises = require('node:readline/promises');
const rl = readlinePromises.createInterface({
input: process.stdin,
output: process.stdout,
});
创建readlinePromises.Interface
实例后,最常见的情况是监听'line'
事件:
rl.on('line', (line) => {
console.log(`Received: ${line}`);
});
如果此实例的terminal
为true
,则output
流定义output.columns
属性并发出{如果列发生更改,则在output
上发生 'resize'
事件(当process.stdout
是 TTY 时,会自动执行此操作)。
使用completer
函数#
completer
函数将用户输入的当前行作为参数,并返回包含 2 个条目的Array
:
- 具有用于补全的匹配条目的
Array
。 - 用于匹配的子字符串。
例如:[[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];
}
completer
函数还可以返回<Promise>,或者是异步的:
async function completer(linePartial) {
await someAsyncWork();
return [['123'], linePartial];
}
回调接口#
类:readline.Interface
#
readline.Interface
类的实例是使用
readline.createInterface()
方法构造的。每个实例都与一个input
可读流和一个output
可写流关联。output
流用于打印到达input
流并从中读取的用户输入的提示。
rl.question(query[, options], callback)
#
query
<string>要写入output
的语句或查询,放在提示符前面。options
<对象>signal
<AbortSignal>(可选)允许使用AbortController
取消question()
。
callback
<Function>使用用户输入调用的回调函数,以响应query
。
rl.question()
方法通过将query
写入output
来显示 query
,等待在input
上提供用户输入,然后调用callback
函数将提供的输入作为第一个参数传递。
调用时,rl.question()
将恢复已暂停的input
流。
如果创建readline.Interface
时将output
设置为null
或
undefined
,则不会写入query
。
传递给rl.question()
的callback
函数不遵循接受Error
对象或null
作为第一个参数的典型模式。使用提供的答案作为唯一参数来调用callback
。
如果在 rl.close()
之后调用rl.question()
将会抛出错误。
用法示例:
rl.question('What is your favorite food? ', (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
使用AbortController
取消问题。
const ac = new AbortController();
const signal = ac.signal;
rl.question('What is your favorite food? ', { signal }, (answer) => {
console.log(`Oh, so your favorite food is ${answer}`);
});
signal.addEventListener('abort', () => {
console.log('The food question timed out');
}, { once: true });
setTimeout(() => ac.abort(), 10000);
readline.clearLine(stream, dir[, callback])
#
stream
<stream.Writable>dir
<数字>-1
:光标左侧1
:光标右侧0
:整行
callback
<Function>操作完成后调用。- 返回:<boolean>
false
如果stream
希望调用代码在继续写入其他数据之前等待'drain'
事件发出;否则true
。
readline.clearLine()
方法以dir
标识的指定方向清除给定TTY流的当前行。
readline.clearScreenDown(stream[, callback])
#
stream
<stream.Writable>callback
<Function>操作完成后调用。- 返回:<boolean>
false
如果stream
希望调用代码在继续写入其他数据之前等待'drain'
事件发出;否则true
。
readline.clearScreenDown()
方法从光标当前位置向下清除给定的TTY流。
readline.createInterface(options)
#
options
<对象>input
<stream.Readable>要侦听的可读流。该选项是必需的。output
<stream.Writable>用于写入读取行数据的可写流。completer
<Function>用于 Tab 自动补全的可选函数。terminal
<boolean>true
是否应将input
和output
流视为 TTY,并写入 ANSI/VT100 转义码到它。 默认值:实例化时检查output
流上的isTTY
。history
<string[]>历史行的初始列表。仅当用户或内部output
检查将terminal
设置为true
时,此选项才有意义 ,否则历史记录缓存机制根本不会初始化。 默认值:[]
。historySize
<number>保留的历史记录行的最大数量。要禁用历史记录,请将此值设置为0
。仅当用户或内部output
检查将terminal
设置为true
时,此选项才有意义 ,否则历史记录缓存机制根本不会初始化。 默认值:30
。removeHistoryDuplicates
<boolean>如果为true
,则当添加到历史记录列表中的新输入行与旧输入行重复时,将从列表中删除旧行。默认值:false
。prompt
<string>要使用的提示字符串。默认值:'> '
。crlfDelay
<number>如果\r
和\n
之间的延迟超过crlfDelay
毫秒,则\r
和\n
将被视为单独的行尾输入。crlfDelay
将被强制为不小于100
的数字 。它可以设置为Infinity
,在这种情况下,\r
后跟\n
将始终被视为单个换行符(这对于 使用{ { {0529}}}行分隔符)。默认值:100
。escapeCodeTimeout
<number>持续时间readline
将等待一个字符(当以毫秒为单位读取不明确的按键序列时,该字符既可以使用到目前为止读取的输入形成完整的按键序列,也可以需要额外的输入来完成更长的按键序列)。 默认值:500
。tabSize
<整数>制表符等于的空格数(最小 1)。 默认值:8
。signal
<AbortSignal>允许使用 AbortSignal 关闭界面。中止信号将在接口上内部调用close
。
- 返回:<readline.Interface>
readline.createInterface()
方法创建一个新的readline.Interface
实例。
const readline = require('node:readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
创建readline.Interface
实例后,最常见的情况是监听'line'
事件:
rl.on('line', (line) => {
console.log(`Received: ${line}`);
});
如果此实例的terminal
为true
,则output
流定义output.columns
属性并发出{如果列发生更改,则在output
上发生 'resize'
事件(当process.stdout
是 TTY 时,会自动执行此操作)。
当使用stdin
作为输入创建readline.Interface
时,程序在收到EOF 字符之前不会终止。要退出而不等待用户输入,请调用process.stdin.unref()
。
使用completer
函数#
completer
函数将用户输入的当前行作为参数,并返回包含 2 个条目的Array
:
- 具有用于补全的匹配条目的
Array
。 - 用于匹配的子字符串。
例如:[[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];
}
如果completer
函数接受两个参数,则可以异步调用它:
function completer(linePartial, callback) {
callback(null, [['123'], linePartial]);
}
readline.cursorTo(stream, x[, y][, callback])
#
stream
<stream.Writable>x
<数字>y
<数字>callback
<Function>操作完成后调用。- 返回:<boolean>
false
如果stream
希望调用代码在继续写入其他数据之前等待'drain'
事件发出;否则true
。
readline.cursorTo()
方法将光标移动到给定TTY stream
中的指定位置。
readline.moveCursor(stream, dx, dy[, callback])
#
stream
<stream.Writable>dx
<数字>dy
<数字>callback
<Function>操作完成后调用。- 返回:<boolean>
false
如果stream
希望调用代码在继续写入其他数据之前等待'drain'
事件发出;否则true
。
readline.moveCursor()
方法将光标相对于给定TTY stream
中的当前位置移动。
readline.emitKeypressEvents(stream[, interface])
#
stream
<stream.Readable>interface
<readline.InterfaceConstructor>
readline.emitKeypressEvents()
方法导致给定的可读
流开始发出与接收到的输入相对应的'keypress'
事件。
(可选)interface
指定一个readline.Interface
实例,在检测到复制粘贴输入时禁用自动完成功能。
如果stream
是TTY,则它必须处于原始模式。
如果
input
是终端,则其input
上的任何 readline 实例都会自动调用此函数。关闭readline
实例不会阻止input
发出'keypress'
事件。
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY)
process.stdin.setRawMode(true);
示例:微型 CLI#
以下示例说明了如何使用readline.Interface
类来实现小型命令行界面:
const readline = require('node:readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'OHAI> ',
});
rl.prompt();
rl.on('line', (line) => {
switch (line.trim()) {
case 'hello':
console.log('world!');
break;
default:
console.log(`Say what? I might have heard '${line.trim()}'`);
break;
}
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
示例:逐行读取文件流#
readline
的一个常见用例是一次一行地使用输入文件。最简单的方法是利用fs.ReadStream
API 以及for await...of
循环:
const fs = require('node:fs');
const readline = require('node:readline');
async function processLineByLine() {
const fileStream = fs.createReadStream('input.txt');
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
// Note: we use the crlfDelay option to recognize all instances of CR LF
// ('\r\n') in input.txt as a single line break.
for await (const line of rl) {
// Each line in input.txt will be successively available here as `line`.
console.log(`Line from file: ${line}`);
}
}
processLineByLine();
或者,可以使用'line'
事件:
const fs = require('node:fs');
const readline = require('node:readline');
const rl = readline.createInterface({
input: fs.createReadStream('sample.txt'),
crlfDelay: Infinity,
});
rl.on('line', (line) => {
console.log(`Line from file: ${line}`);
});
目前,for await...of
循环可能会慢一些。如果async
/ await
流量和速度都很重要,则可以应用混合方法:
const { once } = require('node:events');
const { createReadStream } = require('node:fs');
const { createInterface } = require('node:readline');
(async function processLineByLine() {
try {
const rl = createInterface({
input: createReadStream('big-file.txt'),
crlfDelay: Infinity,
});
rl.on('line', (line) => {
// Process the line.
});
await once(rl, 'close');
console.log('File processed.');
} catch (err) {
console.error(err);
}
})();
TTY 键绑定#
键绑定 | 描述 | 注意 |
---|---|---|
Ctrl+ Shift+Backspace | 删除左侧行 | 不适用于 Linux、Mac 和 Windows |
Ctrl+ Shift+Delete | 删除右行 | 不适用于 Mac |
Ctrl+C | 发出SIGINT 或关闭 readline 实例 |
|
Ctrl+H | 删除左侧 | |
Ctrl+D | 如果当前行为空/EOF,则删除右侧或关闭 readline 实例 | 不适用于 Windows |
Ctrl+U | 删除从当前位置到行首的位置 | |
Ctrl+K | 从当前位置删除到行尾 | |
Ctrl+Y | 猛拉(召回)之前删除的文本 | 仅适用于通过Ctrl+U或Ctrl+删除的文本K |
Meta+Y | 在先前删除的行之间循环 | 仅当最后一次击键为Ctrl+时可用Y |
Ctrl+A | 转到行首 | |
Ctrl+E | 转到行尾 | |
Ctrl+B | 后退一位字符 | |
Ctrl+F | 前进一个字符 | |
Ctrl+L | 清晰的屏幕 | |
Ctrl+N | 下一个历史记录项目 | |
Ctrl+P | 以前的历史记录项目 | |
Ctrl+- | 撤消之前的更改 | 任何发出键代码0x1F 的击键都会执行此操作。在许多终端中,例如xterm ,这绑定到Ctrl+ -。 |
Ctrl+6 | 重做之前的更改 | 许多终端没有默认的重做击键。我们选择关键代码0x1E 来执行重做。在xterm 中,它
默认绑定到Ctrl+ 。6 |
Ctrl+Z | 将正在运行的进程移至后台。输入
fg 并按Enter
返回。 |
不适用于 Windows |
Ctrl+W或Ctrl +Backspace | 向后删除至字边界 | Ctrl+Backspace不适用于 Linux、Mac 和 Windows |
Ctrl+Delete | 向前删除至字边界 | 不适用于 Mac |
Ctrl+Left arrow或 Meta+B | 留下的话 | Ctrl+Left arrow不适用于 Mac |
Ctrl+Right arrow或 Meta+F | 词对了 | Ctrl+Right arrow不适用于 Mac |
Meta+D或Meta +Delete | 删除单词右 | Meta+Delete不适用于 Windows |
Meta+Backspace | 删除左边的单词 | 不适用于 Mac |