Skip to content

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 และเปิดใช้งานโหมด inputMethodใช้สร้าง prompt พร้อมรับข้อมูลจากผู้ใช้
rl.on('line', callback)กำหนด handler เมื่อได้รับข้อมูลหนึ่งบรรทัดEventcallback จะทำงานทุกครั้งที่ผู้ใช้กด Enter
rl.on('close', callback)กำหนด handler เมื่อ interface ถูกปิดEventเกิดขึ้นเมื่อ Ctrl+C, Ctrl+D หรือเรียก rl.close()
rl.close()ปิด readline InterfaceMethodหยุดการทำงานและคืนทรัพยากร
rl.write()เขียนข้อมูลไปยัง output streamMethodใช้เพื่อแสดงข้อความหรือเติมข้อมูลใน input line
rl.getPrompt()รับค่า prompt ปัจจุบันMethodดึงข้อความ prompt ที่กำลังใช้งาน
rl.setPrompt()กำหนดข้อความ promptMethodใช้เปลี่ยนข้อความ 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();