การอ่านข้อมูลจากไฟล์ใน Node.js

ในบทนี้ คุณจะได้เรียนรู้การอ่านข้อมูลจากไฟล์ใน Node.js การอ่านข้อมูลจากไฟล์คือการนำข้อมูลที่เก็บอยู่บนดิสมาใช้งานในโปรแกรม Node.js นั้นมีเมธอดจากโมดูล fs ที่เราสามารถใช้สำหรับอ่านข้อมูลจากไฟล์ได้ และนี่เป็นเนื้อหาในบทนี้

  • การอ่านข้อมูลจากไฟล์ใน Node.js
  • การอ่านข้อมูลจากไฟล์แบบ Synchronous
  • การอ่านข้อมูลจากไฟล์ด้วย Stream

ในบทนี้จะพูดถึงการทำงานกับ Text ไฟล์เท่านั้น เราจะไม่ครอบคลุมถึงการทำงานกับ Binary ไฟล์

การอ่านข้อมูลจากไฟล์ใน Node.js

เพื่ออ่านข้อมูลจากไฟล์บน Node.js คุณสามารถใช้เมธอด readFile จากโมดูล fs ได้ กำหนดให้เรามีไฟล์ myfile.txt ที่อยู่บนดิสและต้องการอ่านข้อมูลเพื่อนำมาใช้งานในโปรแกรม ซึ่งภายในไฟล์มีเนื้อหาดังต่อไปนี้

myfile.txt
This is a first line
This is a second line
And this is a third line

และนี่เป็นโปรแกรมสำหรับอ่านข้อมูลจากไฟล์ดังกล่าว

read_file_example.js
const fs = require('fs');

fs.readFile('./myfile.txt', 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return
    }
    console.log(data);
});

ก่อนเริ่มใช้งานเมธอดสำหรับการอ่านไฟล์ เราได้นำเข้าโมดูล fs ด้วยคำสั่ง

const fs = require('fs');

ออบเจ็ค fs ประกอบไปด้วยเมธอดเป็นจำนวนมากสำหรับทำงานกับไฟล์ ในตัวอย่างนี้เราจะใช้เพียงเมธอดสำหรับการอ่านไฟล์

เมธอด readFile จะอ่านข้อมูลจากไฟล์ทั้งหมดเพียงครั้งเดียว มันรับสามพารามิเตอร์เพื่อทำงาน พารามิเตอร์แรกเป็นชื่อของไฟล์ที่ต้องการอ่าน พารามิเตอร์ที่สอง Encoding สำหรับการอ่าน โดยทั่วไปแล้ว Encoding ที่ใช้มักจะเป็น utf8 แต่คุณสามารถใช้แบบอื่นได้หากต้องการ

พารามิเตอร์สุดท้ายเป็นฟังก์ชัน Callback ที่จะถูกเรียกใช้งานเมื่อการอ่านไฟล์เสร็จสิ้น มันรับสองพารามิเตอร์ได้แก่ err ใช้เพื่อตรวจสอบกว่าการอ่านไฟล์สำเร็จหรือไม่ ถ้าหากการอ่านไฟล์สำเร็จตัวแปรนี้จะมีค่าเป็น null และเราสามารถรับเอาข้อมูลที่อ่านได้จากพารามิเตอร์ data และในกรณีที่การอ่านไฟล์ล้มเหลว ค่าในตัวแปร err จะเป็นข้อความของข้อผิดพลาดที่เกิดขึ้นในระหว่างการอ่านไฟล์

นี่เป็นผลลัพธ์การทำงานของโปรแกรม ไฟล์ได้ถูกอ่านและเราเพียงแสดงข้อมูลที่อ่านได้ออกทางหน้าจอ คุณสามารถนำข้อมูลไปทำอะไรก็ที่ต้องการ

This is a first line
This is a second line
And this is a third line

เมธอด readFile นั้นทำงานแบบ Asynchronous ซึ่งจะไม่บล็อกการทำงานของโปรแกรมในระหว่างการอ่านไฟล์ นี่เป็นรูปแบบการทำงานพื้นฐานที่พบได้ทั่วไปบน Node.js อย่างไรก็ตาม Node.js นั้นมีเมธอดในเวอร์ชัน Synchronous สำหรับการอ่านไฟล์ มาดูกันต่อ

การอ่านข้อมูลจากไฟล์แบบ Synchronous

นอกจากการอ่านไฟล์แบบ Asynchronous แล้ว Node.js ยังมีเวอร์ชันของเมธอดอ่านไฟล์ที่ทำงานในรูปแบบ Synchronous ให้เราสามารถใช้งานได้ด้วย ซึ่งการทำงานของโปรแกรมจะบล็อกจนกว่าการอ่านไฟล์จะเสร็จสิ้น เมธอดที่ว่านี้คือ readFileSync

ในตัวอย่างนี้จะเป็นการอ่านข้อมูลจากไฟล์เดิมแต่จะใช้เมธอด readFileSync แทน

read_file_sync.js
const fs = require('fs');

try {
    let data = fs.readFileSync('./myfile.txt', 'utf8');
    console.log('File read successfully.');
    console.log(data);
} catch (err) {
    console.log(err);
}

เมธอด readFileSync รับเพียงสองพารามิเตอร์คือชื่อของไฟล์ และ Encoding สำหรับการอ่านไฟล์ เนื่องจากเมธอดทำงานในรูปแบบ Synchronous ดังนั้นมันไม่ต้องการฟังก์ชัน Callback เหมือนกับตัวอย่างก่อนหน้า และค่าที่ส่งกลับจากเมธอดจะเป็นข้อมูลที่อ่านได้จากไฟล์โดยตรง

เนื่องจากโปรแกรมทำงานในรูปแบบ Synchronous เราสามารถตรวจสอบข้อผิดพลาดในระหว่างการอ่านไฟล์ได้โดยการใช้คำสั่ง try catch เหมือนการตรวจสอบข้อผิดพลาดปกติในการเขียนโปรแกรมภาษา JavaScript

ทั้งเมธอด readFile และ readFileSync ให้ผลลัพธ์การทำงานที่เหมือนกัน แต่ในการใช้งานคุณอาจต้องเลือกว่าแบบไหนเหมาะสมกับงานของคุณ ขึ้นกับว่าคุณต้องการให้โปรแกรมทำงานแบบ Asynchronous หรือ Synchronous

ในตัวอย่างที่ผ่านมา การอ่านไฟล์ด้วยเมธอด readFile และ readFileSync จะอ่านข้อมูลจากไฟล์เพียงครั้งเดียว นั่นหมายความว่าถ้าหากไฟล์มีขนาดใหญ่ อาจทำให้โปรแกรมต้องรอและใช้หน่วยความจำเป็นจำนวนมากได้ เพื่อแก้ไขปัญหานี้เราสามารถอ่านไฟล์ที่ละส่วนได้โดยการใช้ Stream

การอ่านข้อมูลจากไฟล์ด้วย Stream

แทนที่จะอ่านไฟล์ทั้งหมดเพียงครั้งเดียว เราสามารถอ่านไฟล์ที่ละส่วน (chunk) ได้โดยการใช้ Stream ในโมดูล fs นั้นมีเมธอด createReadStream ที่เราสามารถใช้เพื่อสร้างไฟล์ Stream สำหรับอ่านข้อมูลจากไฟล์แบบทีละ chunk ได้ กำหนดให้เรามีไฟล์ myfile2.txt ที่มีเนื้อหาดังต่อไปนี้

myfile2.txt
marcuscode
node.js
2021

จากนั้นเราเขียนโปรแกรมเพื่ออ่านไฟล์นี้ด้วย Stream นี่เป็นโค้ดของโปรแกรม

stream_read_example.js
const fs = require('fs');

const readable = fs.createReadStream('./myfile2.txt');
readable.setEncoding('utf8');

const chunks = [];

readable.on('readable', () => {
    let chunk;
    while (null !== (chunk = readable.read())) {
        chunks.push(chunk);
        console.log('chunk:', chunk);
    }
});

readable.on('end', () => {
    const content = chunks.join('');
    console.log('---\nFile read successfully.');
    console.log(content);
});

และนี่เป็นผลลัพธ์การทำงานของโปรแกรม

chunk: marcuscode
node.js
2021
---
File read successfully.
marcuscode
node.js
2021

ก่อนอื่นเราสร้างออบเจ็ค Stream ที่เชื่อมต่อกับไฟล์ด้วยเมธอด createReadStream ที่จะใช้สำหรับอ่านไฟล์ เมธอดนี้รับพารามิเตอร์เป็นชื่อของไฟล์ จากนั้นเป็นการกำหนด Encoding สำหรับการอ่านด้วยเมธอด setEncoding เป็น utf8

const chunks = [];

นี่เป็นการประกาศตัวแปรอาเรย์ chunks สำหรับเก็บข้อมูลทั้งหมดที่จะอ่านมาได้จากไฟล์

readable.on('readable', () => {
    let chunk;
    while (null !== (chunk = readable.read())) {
        chunks.push(chunk);
        console.log('chunk:', chunk);
    }
});

เพื่ออ่านข้อมูลจากไฟล์ เราใช้เมธอด on สำหรับตรวจสอบ Event readable ที่จะเกิดขึ้นเมื่อมีข้อมูลใน Stream ที่สามารถอ่านได้ และใช้คำสั่ง while loop เพื่อวนอ่านข้อมูลจาก Stream ที่ละ chunk ด้วยเมธอด read ทุกครั้งที่ได้รับข้อมูล เราแสดงค่าที่อ่านมาได้ออกทางหน้าจอเพื่อดูว่าโปรแกรมทำงานอย่างไร

chunk = readable.read()

และอย่างที่คุณเห็น ข้อมูลทั้งหมดในไฟล์ถูกอ่านออกมาเพียงครั้งเดียวโดยเมธอด read ที่เป็นเช่นนี้เพราะมันจะพยายามอ่านข้อมูลจาก Stream ให้ได้มากที่สุดเท่าที่เป็นไปได้ ซึ่งการทำงานในรูปแบบนี้จะไม่แตกต่างไปจากสองตัวอย่างก่อนหน้าที่เป็นการอ่านข้อมูลทั้งหมดเพียงครั้งเดียว

อย่างไรก็ตาม ในการใช้งานเมธอด read เราสามารถควบคุมขนาดข้อมูลที่ต้องการอ่านในแต่ละ chunk ได้ และเพื่อทำเช่นนี้ เราสามารถกำหนดขนาดของข้อมูลที่ต้องการอ่านได้โดยส่งเป็นพารามิเตอร์ของเมธอด นี่เป็นตัวอย่าง

chunk = readable.read(4)

นี่เป็นการกำหนดให้เมธอด read อ่านข้อมูลทีละ 4 ไบต์ และมันจะวนอ่านข้อมูลจาก Stream จนกว่าข้อมูลที่ได้รับจะเป็น null ซึ่งหมายความว่าไม่มีข้อมูลเหลือให้อ่านแล้ว และหมายถึงการอ่านข้อมูลเสร็จสิ้น

นี่เป็นผลลัพธ์การทำงานของโปรแกรมหลังจากกำหนดขนาดของการอ่าน

readable
chunk: marc
chunk: usco
chunk: de

chunk: node
chunk: .js
chunk:
202
readable
chunk: 1
---
File read successfully.
marcuscode
node.js
2021

จะเห็นว่าการแสดงผลในแต่ละ chunk เปลี่ยนไปเมื่อเรากำหนดขนาดของการอ่านทีละ 4 ไบต์ และข้อมูลจะถูกอ่านออกมาทีละ 4 ตัวอักษร นั่นเป็นเพราะว่าในภาษา JavaScript นั้นหนึ่งตัวอักษรใน Encoding แบบ utf8 มีขนาดเท่ากับ 1 ไบต์

readable.on('end', () => {
    const content = chunks.join('');
    console.log('---\nFile read successfully.');
    console.log(content);
});

และสุดท้ายเมื่อการอ่านเสร็จสิ้นจะเกิด Event end ขึ้น เราได้ทำการรวบรวมข้อมูลทั้งหมดที่อ่านได้ในตัวแปร chunks เข้าเป็น String ด้วยเมธอด join และได้รับเนื้อหาของไฟล์ทั้งหมดในตัวแปร content และแสดงผลออกทางหน้าจอ

อย่างไรก็ตาม คุณสามารถประมวลผลแต่ละ chunk อย่างเป็นอิสระต่อกันได้ โดยไม่จำเป็นต้องรอให้ครบทุก chunk เหมือนกับที่เราทำ ถ้าหากว่าโปรแกรมของคุณเหมาะสมที่จะทำงานในรูปแบบนี้ ตัวอย่างของแอพพลิเคชันในลักษณะนี้ เช่น โปรแกรมเล่นวิดีโอ หรือการสตรีมบนเว็บ เป็นต้น

ในการอ่านไฟล์ หากคุณไม่ได้กำหนด Encoding ของการอ่าน การอ่านไฟล์ของเมธอด read จะถูกส่งข้อมูลกลับมาในรูปแบบของ Buffer ซึ่งเป็นข้อมูลแบบ Binary และนี่เป็นรูปแบบการทำงานพื้นฐานของ Stream บน Node.js

ในบทนี้ คุณได้เรียนรู้การอ่านข้อมูลจากไฟล์ใน Node.js โดยการใช้งานเมธอดจากโมดูล fs เราได้แสดงให้คุณเห็นถึงวิธีการใช้งานเมธอดทั้งในรูปแบบ Asynchronous และ Synchronous ในการอ่านไฟล์ และวิธีการอ่านไฟล์อย่างมีประสิทธิภาพโดยใช้ Stream