Node.js v25.0.0 文件
- Node.js v25.0.0
- 目錄
-
索引
- 斷言測試
- 非同步上下文跟蹤
- 非同步鉤子
- 緩衝區
- C++ 外掛
- 使用 Node-API 的 C/C++ 外掛
- C++ 嵌入器 API
- 子程序
- 叢集
- 命令列選項
- 控制檯
- 加密
- 偵錯程式
- 已棄用的 API
- 診斷通道
- DNS
- 域
- 環境變數
- 錯誤
- 事件
- 檔案系統
- 全域性物件
- HTTP
- HTTP/2
- HTTPS
- 檢查器
- 國際化
- 模組:CommonJS 模組
- 模組:ECMAScript 模組
- 模組:
node:moduleAPI - 模組:包
- 模組:TypeScript
- 網路
- 作業系統
- 路徑
- 效能鉤子
- 許可權
- 程序
- Punycode
- 查詢字串
- 逐行讀取
- REPL
- 報告
- 單一可執行檔案應用
- SQLite
- 流
- 字串解碼器
- 測試執行器
- 定時器
- TLS/SSL
- 跟蹤事件
- TTY
- UDP/資料報
- URL
- 實用工具
- V8
- 虛擬機器
- WASI
- Web Crypto API
- Web Streams API
- 工作執行緒
- Zlib
- 其他版本
- 選項
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#
- 繼承自:<EventEmitter>
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,並且InterfaceConstructor例項上沒有註冊'SIGINT'事件監聽器。
呼叫監聽器函式時不傳遞任何引數。
一旦發出 'close' 事件,InterfaceConstructor 例項就完成了。
事件:'line'#
每當 input 流接收到行尾輸入(\n、\r 或 \r\n)時,就會觸發 'line' 事件。這通常在使用者按下 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'#
當一個 Node.js 程序先前使用 Ctrl+Z(即 SIGTSTP)移至後臺,然後使用 fg(1p) 重新帶回前臺時,會觸發 'SIGCONT' 事件。
如果在 SIGTSTP 請求之前 input 流被暫停,則不會觸發此事件。
呼叫監聽器函式時不傳遞任何引數。
rl.on('SIGCONT', () => {
// `prompt` will automatically resume the stream
rl.prompt();
});
'SIGCONT' 事件在 Windows 上不支援。
事件:'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.');
});
'SIGTSTP' 事件在 Windows 上不支援。
rl.close()#
rl.close() 方法關閉 InterfaceConstructor 例項並放棄對 input 和 output 流的控制。呼叫時,將觸發 'close' 事件。
呼叫 rl.close() 不會立即停止由 InterfaceConstructor 例項觸發的其他事件(包括 'line')。
rl[Symbol.dispose]()#
rl.close() 的別名。
rl.pause()#
rl.pause() 方法暫停 input 流,允許在必要時稍後恢復。
呼叫 rl.pause() 不會立即暫停由 InterfaceConstructor 例項觸發的其他事件(包括 'line')。
rl.prompt([preserveCursor])#
preserveCursor<boolean> 如果為true,則防止游標位置被重置為0。
rl.prompt() 方法將 InterfaceConstructor 例項配置的 prompt 寫入 output 的新行,以便為使用者提供一個新的位置來輸入。
呼叫時,如果 input 流已暫停,rl.prompt() 將恢復它。
如果建立 InterfaceConstructor 時將 output 設定為 null 或 undefined,則不會寫入提示。
rl.resume()#
如果 input 流已暫停,rl.resume() 方法會恢復它。
rl.write(data[, key])#
rl.write() 方法將 data 或由 key 標識的鍵序列寫入 output。僅當 output 是 TTY 文字終端時,才支援 key 引數。有關組合鍵的列表,請參見 TTY 快捷鍵繫結。
如果指定了 key,則忽略 data。
呼叫時,如果 input 流已暫停,rl.write() 將恢復它。
如果建立 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#
- 型別:<string>
節點正在處理的當前輸入資料。
當從 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#
- 型別:<number> | <undefined>
游標相對於 rl.line 的位置。
當從 TTY 流讀取輸入時,這將跟蹤當前游標在輸入字串中的位置。游標的位置決定了在處理輸入時將被修改的輸入字串部分,以及終端游標將呈現的列。
Promises API#
類:readlinePromises.Interface#
readlinePromises.Interface 類的例項是使用 readlinePromises.createInterface() 方法構造的。每個例項都與一個 input 可讀流和一個 output 可寫流相關聯。output 流用於為到達 input 流並從中讀取的使用者輸入列印提示。
rl.question(query[, options])#
query<string> 要寫入output的語句或查詢,前置於提示符。options<Object>signal<AbortSignal> 可選地允許使用AbortSignal取消question()。
- 返回:<Promise> 一個 Promise,它會在使用者響應
query的輸入時被 fulfill。
rl.question() 方法透過將 query 寫入 output 來顯示它,等待使用者在 input 上提供輸入,然後呼叫 callback 函式,將提供的輸入作為第一個引數傳遞。
呼叫時,如果 input 流已暫停,rl.question() 將恢復它。
如果建立 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<Object>autoCommit<boolean> 如果為true,則無需呼叫rl.commit()。
rl.clearLine(dir)#
dir<integer>-1: 從游標向左1: 從游標向右0: 整行
- 返回:this
rl.clearLine() 方法向內部待處理操作列表新增一個操作,該操作以 dir 標識的指定方向清除關聯 stream 的當前行。呼叫 rl.commit() 以檢視此方法的效果,除非在建構函式中傳遞了 autoCommit: true。
rl.clearScreenDown()#
- 返回:this
rl.clearScreenDown() 方法向內部待處理操作列表新增一個操作,該操作從游標當前位置向下清除關聯的流。呼叫 rl.commit() 以檢視此方法的效果,除非在建構函式中傳遞了 autoCommit: true。
rl.cursorTo(x[, y])#
rl.cursorTo() 方法向內部待處理操作列表新增一個操作,該操作將游標移動到關聯 stream 中的指定位置。呼叫 rl.commit() 以檢視此方法的效果,除非在建構函式中傳遞了 autoCommit: true。
rl.moveCursor(dx, dy)#
rl.moveCursor() 方法向內部待處理操作列表新增一個操作,該操作將游標相對於其在關聯 stream 中的當前位置進行移動。呼叫 rl.commit() 以檢視此方法的效果,除非在建構函式中傳遞了 autoCommit: true。
readlinePromises.createInterface(options)#
options<Object>input<stream.Readable> 要監聽的可讀流。此選項是必需的。output<stream.Writable> 要寫入 readline 資料的可寫流。completer<Function> 一個可選函式,用於 Tab 自動補全。terminal<boolean> 如果input和output流應被視為 TTY,並且應向其寫入 ANSI/VT100 轉義碼,則為true。預設值:在例項化時檢查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將始終被視為單個換行符(這對於讀取具有\r\n行分隔符的檔案可能是合理的)。預設值:100。escapeCodeTimeout<number>readlinePromises將等待一個字元的持續時間(以毫秒為單位,當讀取一個模糊的鍵序列時,該序列既可以使用目前為止讀取的輸入形成一個完整的鍵序列,也可以接受額外的輸入來完成一個更長的鍵序列)。預設值:500。tabSize<integer> 一個製表符等於的空格數(最小為 1)。預設值:8。signal<AbortSignal> 允許使用 AbortSignal 關閉介面。
- 返回:<readlinePromises.Interface>
readlinePromises.createInterface() 方法建立一個新的 readlinePromises.Interface 例項。
import { createInterface } from 'node:readline/promises';
import { stdin, stdout } from 'node:process';
const rl = createInterface({
input: stdin,
output: stdout,
});const { createInterface } = require('node:readline/promises');
const rl = 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 時會自動執行此操作),則 output 流將獲得最佳相容性。
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];
}
回撥 API#
類:readline.Interface#
readline.Interface 類的例項是使用 readline.createInterface() 方法構造的。每個例項都與一個 input 可讀流和一個 output 可寫流相關聯。output 流用於為到達 input 流並從中讀取的使用者輸入列印提示。
rl.question(query[, options], callback)#
query<string> 要寫入output的語句或查詢,前置於提示符。options<Object>signal<AbortSignal> 可選地允許使用AbortController取消question()。
callback<Function> 一個回撥函式,在使用者響應query的輸入時被呼叫。
rl.question() 方法透過將 query 寫入 output 來顯示它,等待使用者在 input 上提供輸入,然後呼叫 callback 函式,將提供的輸入作為第一個引數傳遞。
呼叫時,如果 input 流已暫停,rl.question() 將恢復它。
如果建立 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<number>-1: 從游標向左1: 從游標向右0: 整行
callback<Function> 操作完成後呼叫。- 返回:<boolean> 如果
stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.clearLine() 方法以 dir 標識的指定方向清除給定的 TTY 流的當前行。
readline.clearScreenDown(stream[, callback])#
stream<stream.Writable>callback<Function> 操作完成後呼叫。- 返回:<boolean> 如果
stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.clearScreenDown() 方法從游標當前位置向下清除給定的 TTY 流。
readline.createInterface(options)#
options<Object>input<stream.Readable> 要監聽的可讀流。此選項是必需的。output<stream.Writable> 要寫入 readline 資料的可寫流。completer<Function> 一個可選函式,用於 Tab 自動補全。terminal<boolean> 如果input和output流應被視為 TTY,並且應向其寫入 ANSI/VT100 轉義碼,則為true。預設值:在例項化時檢查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將始終被視為單個換行符(這對於讀取具有\r\n行分隔符的檔案可能是合理的)。預設值:100。escapeCodeTimeout<number>readline將等待一個字元的持續時間(以毫秒為單位,當讀取一個模糊的鍵序列時,該序列既可以使用目前為止讀取的輸入形成一個完整的鍵序列,也可以接受額外的輸入來完成一個更長的鍵序列)。預設值:500。tabSize<integer> 一個製表符等於的空格數(最小為 1)。預設值:8。signal<AbortSignal> 允許使用 AbortSignal 關閉介面。中止訊號將在內部呼叫介面上的close。
- 返回:<readline.Interface>
readline.createInterface() 方法建立一個新的 readline.Interface 例項。
import { createInterface } from 'node:readline';
import { stdin, stdout } from 'node:process';
const rl = createInterface({
input: stdin,
output: stdout,
});const { createInterface } = require('node:readline');
const rl = 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 時會自動執行此操作),則 output 流將獲得最佳相容性。
當使用 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<number>y<number>callback<Function> 操作完成後呼叫。- 返回:<boolean> 如果
stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.cursorTo() 方法將游標移動到給定的 TTY stream 中的指定位置。
readline.moveCursor(stream, dx, dy[, callback])#
stream<stream.Writable>dx<number>dy<number>callback<Function> 操作完成後呼叫。- 返回:<boolean> 如果
stream希望呼叫程式碼在繼續寫入額外資料之前等待'drain'事件觸發,則為false;否則為true。
readline.moveCursor() 方法將游標相對於其在給定的 TTY stream 中的當前位置進行移動。
readline.emitKeypressEvents(stream[, interface])#
stream<stream.Readable>interface<readline.InterfaceConstructor>
readline.emitKeypressEvents() 方法使給定的可讀流開始觸發與接收到的輸入相對應的 'keypress' 事件。
可選地,interface 指定一個 readline.Interface 例項,當檢測到複製貼上的輸入時,將為其停用自動補全。
如果 stream 是一個 TTY,那麼它必須處於原始模式。
如果 input 是一個終端,任何 readline 例項都會在其 input 上自動呼叫此方法。關閉 readline 例項不會停止 input 觸發 'keypress' 事件。
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY)
process.stdin.setRawMode(true);
示例:微型 CLI#
以下示例說明了如何使用 readline.Interface 類來實現一個小型命令列介面:
import { createInterface } from 'node:readline';
import { exit, stdin, stdout } from 'node:process';
const rl = createInterface({
input: stdin,
output: 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!');
exit(0);
});const { createInterface } = require('node:readline');
const rl = 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 迴圈:
import { createReadStream } from 'node:fs';
import { createInterface } from 'node:readline';
async function processLineByLine() {
const fileStream = createReadStream('input.txt');
const rl = 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();const { createReadStream } = require('node:fs');
const { createInterface } = require('node:readline');
async function processLineByLine() {
const fileStream = createReadStream('input.txt');
const rl = 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' 事件:
import { createReadStream } from 'node:fs';
import { createInterface } from 'node:readline';
const rl = createInterface({
input: createReadStream('sample.txt'),
crlfDelay: Infinity,
});
rl.on('line', (line) => {
console.log(`Line from file: ${line}`);
});const { createReadStream } = require('node:fs');
const { createInterface } = require('node:readline');
const rl = createInterface({
input: createReadStream('sample.txt'),
crlfDelay: Infinity,
});
rl.on('line', (line) => {
console.log(`Line from file: ${line}`);
});
目前,for await...of 迴圈可能會慢一些。如果 async / await 流程和速度都至關重要,可以採用混合方法:
import { once } from 'node:events';
import { createReadStream } from 'node:fs';
import { createInterface } from '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);
}
})();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 或 Meta+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 上無效 |