Dark mode
readline
readline เป็นโมดูลในตัวของ Node.js ที่ใช้อ่านข้อมูลจากกระแสข้อมูลแบบอ่านทีละบรรทัด (line-by-line) เช่น การอ่านข้อมูลจากแป้นพิมพ์หรือไฟล์ มักใช้สำหรับการสร้าง CLI (Command Line Interface) ที่โต้ตอบกับผู้ใช้
import { createInterface } from 'node:readline';
API | คำอธิบาย | ลักษณะ | คำอธิบายเพิ่มเติม |
---|---|---|---|
createInterface | สร้าง interface สำหรับอ่านข้อมูลทีละบรรทัด | Function | รับพารามิเตอร์เป็น object ที่กำหนด input และ output stream |
readline.Interface | คลาสที่ใช้จัดการการอ่านข้อมูลทีละบรรทัด | Class | มีเมธอดต่างๆ เช่น question(), prompt(), close() |
rl.question() | แสดงคำถามและรอรับคำตอบจากผู้ใช้ | Method | รับพารามิเตอร์เป็นคำถามและ callback function สำหรับจัดการกับคำตอบ |
rl.prompt() | แสดง prompt และเปิดใช้งานโหมด input | Method | ใช้สร้าง prompt พร้อมรับข้อมูลจากผู้ใช้ |
rl.on('line', callback) | กำหนด handler เมื่อได้รับข้อมูลหนึ่งบรรทัด | Event | callback จะทำงานทุกครั้งที่ผู้ใช้กด Enter |
rl.on('close', callback) | กำหนด handler เมื่อ interface ถูกปิด | Event | เกิดขึ้นเมื่อ Ctrl+C, Ctrl+D หรือเรียก rl.close() |
rl.close() | ปิด readline Interface | Method | หยุดการทำงานและคืนทรัพยากร |
rl.write() | เขียนข้อมูลไปยัง output stream | Method | ใช้เพื่อแสดงข้อความหรือเติมข้อมูลใน input line |
rl.getPrompt() | รับค่า prompt ปัจจุบัน | Method | ดึงข้อความ prompt ที่กำลังใช้งาน |
rl.setPrompt() | กำหนดข้อความ prompt | Method | ใช้เปลี่ยนข้อความ prompt |
ตัวอย่าง
การสร้างโปรแกรมถาม-ตอบอย่างง่าย
js
import * as readline from "node:readline";
// สร้าง readline interface ด้วย stdin และ stdout
const rl = readline.createInterface({
input: process.stdin, // รับข้อมูลจากแป้นพิมพ์
output: process.stdout, // แสดงผลไปที่หน้าจอ
});
// ใช้ method question เพื่อถามคำถาม
rl.question("คุณชื่ออะไร? ", (name) => {
console.log(`สวัสดี ${name}!`);
// ถามคำถามต่อไป
rl.question("คุณอายุเท่าไร? ", (age) => {
console.log(`คุณอายุ ${age} ปี`);
// ปิด interface เมื่อเสร็จสิ้น
rl.close();
});
});
// เมื่อ interface ถูกปิด
rl.on("close", () => {
console.log("ขอบคุณที่ใช้งานโปรแกรมของเรา!");
process.exit(0);
});
การสร้าง CLI แบบโต้ตอบต่อเนื่อง
js
import * as readline from "node:readline";
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: "โปรแกรมคำนวณ> ", // กำหนด prompt สำหรับผู้ใช้
});
// แสดง prompt เริ่มต้น
rl.prompt();
// รับฟังเหตุการณ์เมื่อผู้ใช้ป้อนข้อมูล
rl.on("line", (line) => {
line = line.trim();
// ตรวจสอบคำสั่งออกจากโปรแกรม
if (line === "ออก" || line === "exit") {
rl.close();
return;
}
try {
// พยายามประมวลผลสูตรทางคณิตศาสตร์
const result = eval(line);
console.log(`ผลลัพธ์: ${result}`);
} catch (err) {
console.log("ข้อผิดพลาด: โปรดป้อนสูตรคำนวณที่ถูกต้อง");
}
// แสดง prompt อีกครั้งเพื่อรับข้อมูลใหม่
rl.prompt();
});
// จัดการเมื่อผู้ใช้ปิดโปรแกรม
rl.on("close", () => {
console.log("\nขอบคุณที่ใช้งานโปรแกรมคำนวณ!");
process.exit(0);
});
การสร้างเมนูตัวเลือกด้วย readline
js
import * as readline from "node:readline";
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// ฟังก์ชันแสดงเมนู
function showMenu() {
console.log("\n==== เมนูหลัก ====");
console.log("1. ข้อมูลระบบ");
console.log("2. คำนวณพื้นที่วงกลม");
console.log("3. ทายตัวเลข");
console.log("0. ออกจากโปรแกรม");
rl.question("\nเลือกหมายเลขเมนู: ", handleMenuChoice);
}
// ฟังก์ชันจัดการตัวเลือกเมนู
function handleMenuChoice(choice) {
switch (choice) {
case "1":
showSystemInfo();
break;
case "2":
calculateCircleArea();
break;
case "3":
guessNumberGame();
break;
case "0":
console.log("ขอบคุณที่ใช้งานโปรแกรม!");
rl.close();
return;
default:
console.log("ตัวเลือกไม่ถูกต้อง โปรดเลือกใหม่");
showMenu();
return;
}
}
// ฟังก์ชันข้อมูลระบบ
function showSystemInfo() {
console.log("\n--- ข้อมูลระบบ ---");
console.log(`ระบบปฏิบัติการ: ${process.platform}`);
console.log(
`หน่วยความจำที่ใช้: ${
Math.round(process.memoryUsage().heapUsed / 1024 / 1024)
} MB`,
);
console.log(`เวลาที่ระบบทำงาน: ${Math.floor(process.uptime())} วินาที`);
// กลับไปเมนูหลัก
rl.question("\nกด Enter เพื่อกลับไปเมนูหลัก... ", showMenu);
}
// ฟังก์ชันคำนวณพื้นที่วงกลม
function calculateCircleArea() {
rl.question("\nโปรดป้อนรัศมีของวงกลม: ", (radius) => {
const r = parseFloat(radius);
if (isNaN(r) || r <= 0) {
console.log("รัศมีไม่ถูกต้อง โปรดป้อนเป็นตัวเลขที่มากกว่า 0");
} else {
const area = Math.PI * r * r;
console.log(`พื้นที่วงกลม: ${area.toFixed(2)} ตารางหน่วย`);
}
// กลับไปเมนูหลัก
rl.question("\nกด Enter เพื่อกลับไปเมนูหลัก... ", showMenu);
});
}
// ฟังก์ชันเกมทายตัวเลข
function guessNumberGame() {
const targetNumber = Math.floor(Math.random() * 100) + 1; // สุ่มเลข 1-100
let attempts = 0;
console.log("\n--- เกมทายตัวเลข ---");
console.log("ระบบได้สุ่มตัวเลขระหว่าง 1-100 ไว้แล้ว ลองทายดู!");
function makeGuess() {
rl.question("ทายตัวเลข: ", (guess) => {
const num = parseInt(guess);
attempts++;
if (isNaN(num)) {
console.log("โปรดป้อนตัวเลขเท่านั้น");
makeGuess();
} else if (num < targetNumber) {
console.log("น้อยเกินไป! ลองอีกครั้ง");
makeGuess();
} else if (num > targetNumber) {
console.log("มากเกินไป! ลองอีกครั้ง");
makeGuess();
} else {
console.log(`ถูกต้อง! คุณทายถูกในครั้งที่ ${attempts}`);
rl.question("\nกด Enter เพื่อกลับไปเมนูหลัก... ", showMenu);
}
});
}
makeGuess();
}
// เริ่มโปรแกรมที่เมนูหลัก
showMenu();
การอ่านไฟล์ทีละบรรทัด
js
import * as fs from "node:fs";
import * as readline from "node:readline";
// สร้าง readline interface จาก filestream
const fileStream = fs.createReadStream("example.txt");
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity, // ทำให้รองรับทั้ง \r\n และ \n เป็นตัวแบ่งบรรทัด
});
// นับจำนวนบรรทัด
let lineCount = 0;
// อ่านไฟล์ทีละบรรทัด
rl.on("line", (line) => {
lineCount++;
console.log(`บรรทัดที่ ${lineCount}: ${line}`);
});
// เมื่ออ่านไฟล์เสร็จ
rl.on("close", () => {
console.log(`ไฟล์มีทั้งหมด ${lineCount} บรรทัด`);
});
การสร้าง CLI เพื่อค้นหาในไฟล์
js
import * as fs from "node:fs";
import * as readline from "node:readline";
import { promisify } from "node:util";
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
// แปลง callback-based เป็น promise-based
const question = promisify(rl.question).bind(rl);
async function searchInFile() {
try {
// ถามชื่อไฟล์
const filename = await question("ป้อนชื่อไฟล์ที่ต้องการค้นหา: ");
// ตรวจสอบว่าไฟล์มีอยู่จริงหรือไม่
if (!fs.existsSync(filename)) {
console.log("ไฟล์ไม่มีอยู่ โปรดตรวจสอบชื่อไฟล์");
return await searchInFile();
}
// ถามคำค้นหา
const searchTerm = await question("ป้อนคำที่ต้องการค้นหา: ");
// สร้าง readline interface สำหรับอ่านไฟล์
const fileStream = fs.createReadStream(filename);
const fileRl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
let lineNumber = 0;
let matchCount = 0;
// ตรวจสอบแต่ละบรรทัด
for await (const line of fileRl) {
lineNumber++;
if (line.includes(searchTerm)) {
matchCount++;
console.log(`พบที่บรรทัด ${lineNumber}: ${line}`);
}
}
// แสดงผลสรุป
console.log(`\nผลการค้นหา "${searchTerm}" ในไฟล์ ${filename}:`);
console.log(`พบทั้งหมด ${matchCount} รายการ`);
// ถามว่าต้องการค้นหาอีกหรือไม่
const another = await question("\nต้องการค้นหาอีกหรือไม่? (y/n): ");
if (another.toLowerCase() === "y") {
await searchInFile();
} else {
console.log("ขอบคุณที่ใช้งานโปรแกรมค้นหา!");
rl.close();
}
} catch (error) {
console.error("เกิดข้อผิดพลาด:", error.message);
rl.close();
}
}
// เริ่มโปรแกรม
searchInFile();