في هذا الدرس من سلسلة شرح nodejs بالعربي ستتعلم كيف تقوم بقراءة ملف في بيئة nodejs باستخدام fs module.

ما هي مكتبة fs في nodejs ؟

مكتبة fs هي اختصار لـ file system وتعني نظام الملفات وهي مكتبة داخلية في nodejs حيث تمكنك من التعامل مع الملفات سواء قراءة ملف أو كتابة ملف او انشاء ملف او تعديله، وربما تتسائل ماذا ستستفيد من هذه المكتبة أثناء تطويرك لموقع باستخدام nodejs ؟

دعني اخبرك عزيزي المبرمج ان هذه المكتبة مهمة للغاية فمثلا تخيل معي انك تقوم ببرمجة موقع وعند طلب مثلا الصفحة الرئيسية تريد أن ترسل صفحة html لعرضها، فهنا انت بحاجة إلى مكتبة fs لقراءة ملف html هذا الذي تريد ارساله ومن ثم ترسله.

طرق قراءة ملف باستخدام fs module في nodejs

يوجد ثلاث طرق لكي تتمك من قراءة ملف باستخدام fs module في بيئة nodejs

1- استخدام دالة “readFile” كالأتي:
في البداية سنقوم باستدعاء مكتبة fs داخل ملف الجافا سكريبت

const fs = require("fs");

بعد ذلك سنقوم باستخدام الدالة، وهذه الدالة تأخذ معاملين وهو مسار الملف الذي تريد قراءته، فإذا كان الملف الذي تريد قرائته موجود جانب ملف الجافا سكريبت الذي تكتب فيه الكود مباشرة فيمكنك ان تقوم بكتابة اسم الملف وامتداده مباشرة كما بالشكل التالي:

const fs = require("fs");
fs.readFiel("index.html",function () {});

أما المعامل الثاني فهو callback أو دالة يتم استدعائها بعد البدء في قراءة الملف وهذه الدالة يوجد بداخلها معاملين اثنين الأول “error” وهذا المعامل يتم حفظ فيه أي خطأ يحدث اثناء قراءة الملف إذا لم يكن الملف غير موجود أو أي خطأ يحدث، أما المعامل الثاني فيمثل “data” وهذا يعني البيانات أو المحتوى الذي تم قراءته من الملف لتستخدمه بعد ذلك كما تريد وإليك المثال التالي الذي سنطبع فيه الخطأ إذا وجد في الكونسول وإذا وجدت البيانات سنقوم بطباعتها أيضا في الكونسول:

const fs = require("fs");
fs.readFile("index.html",function (err, data) {
   if (err) {
      console.log(err);
   }
   if(data) {
     console.log(data)
  }
});

2- الدالة الثانية وهي دالة “readFileSync” وهذه الدالة شبيهة للغاية بالدالة السابقة إلا أنها تعتمد على اسلوب المزامنة في nodejs أو ما يعرف بـ “nodejs synchronous” وفيه لا يتم استدعاء دالة callback لتنفيذها عند البدء في قراءة الملف ولكن يتم وضع دالة “readFielSync” داخل “try & catch block” للتحقق من الخطأ إذا لم يكن المسار صحيح ويتم استخدام الدالة كما يظهر في الكود التالي:

const fs = require("fs");
try {
  let html = fs.readFileSync("index.html");
  console.log(html);
} catch(err) {
   console.log(err)
}

3- الطريقة الثالثة وهي دالة “createReadStream” وهذه الدالة تقوم بانشاء stream يتم فيه وضع البيانات التي يتم قراءتها من الملف وتأخذ أول معامل وهو مسار الملف الذي تريد قرائته كما في المثال التالي:

const fs = require("fs");
let stream = fs.createReadStream("index.html");

الأن إذا قمت بطباعة المتغير “stream” الذي قمت بتعريفه في الكود السابق سيتم طباعة اوبجيكت بداخله عديد من الخواص والدوال، وربما تسأل نفسك الأن كيف يمكنك طباعة محتوى الملف الذي تم قرائته، لذلك يجب عزيزي المبرمج أن تفهم ما هي طريقة عمل دالة “createReadStream” في بيئة nodejs .

طريقة عمل هذه الدالة أنها تقوم بتجزئة الملف الذي تريد قراءته إلى عدة أجزاء صغيرة وتقوم بقراءة كل جزء على ثم إرساله لذلك حتى تتمكن من رؤية المحتوى كاملا فيجب ان تنشئ متغير تقوم باضافة كل قطعة صغيرة من هذا الملف وحتى تتمكن من فعل ذلك فانك تقوم باستخدام دالة يتم إطلاقها عند قراءة الملف كالتالي:

stream.on("data", (chunck) => {
})

هذه الدالة تعني أنك تخبر البرنامج عندما يكون محتوى أو بيانات داخل الملف يتم قرائتها فتقوم بإطلاق callback أو دالة أخرى لها معامل واحد وهذا المعامل يمثل كل قطعة يتم قراءتها من الملف ويمكنك حفظها في متغير :

let data = "";
stream.on("data", (chunck) => {
    data += chunck;
})

الأن إذا حاولت طبع متغير “data” فلن يطبع لك شئ لأن البرنامج لا يعلم متى سينتهي من قراءة الملف لذلك يجب ان تستدعي دالة أخرى وهي :

strean.on("end", function () {});

وهذه الدالة لها براميتر أو معامل ثاني وهو callback فانكشن أو دالة يتم استدعائها عند الانتهاء من قراءة الملف وبداخله يمكنك طباعة متغير data

const fs = require("fs");
let stream = fs.createReadStream("index.html");
let data = "";
stream.on("data", (chunck) => {
    data += chunck;
})
stream.on("end", () => {
    console.log(data);
})

الفرق بين دالة “createReadStream” و “readFile” ودالة “readFileSync” في nodejs

الفرق بين دالة “readFile” ودالة “readFileSync” بسيط وهو أن الأولى تستخدم طريقة الـ async أو ما تعرف بغير المزامنة أي تقوم بقراءة الملف وأثناء قراءة هذا الملف يقوم البرنامج بتنفيذ عدد من الدوال والأكواد الأخرى أما الدالة الثانية تستخدم طريقة المزامنة أي تقوم بإيقاف ما تحتها من سطور أو من دوال برمجية حتى يتم قراءة الملف كاملا، ويعيب كلا من هاتين الدالتين أنهما يقومان بقراءة الملف كاملا وحفظه في الذاكرة ثم بعد ذلك طبعه في الكونسول أو ارساله كما تريد والمشكلة هنا أنه إذا كان الملف كبير جدا فأنت في مشكلة أن الذاكرة ستمتلئ بسرعة لأن الملف بالكامل سيتم حفظه في الذاكرة ثم بعد ذلك عمل ما تريد وهذا ما يميز الدالة الثالثة والتي قد تمكنك من ارسال الملف أو طبعه قطعة قطعة دون حفظ محتوى الملف كامل في الذاكرة حتى الانتهاء من قراءته وذلك يكون باستخدام دالة pipe والتي تقوم بضخ أو ارسال كل قطعة من الملف يقوم البرنمج بقرائتها، وهذه الدالة تستخدم غالبا في عملية قراءة الملفات الكبيرة مثل الفيديو وملفات الصوت وغيرها، وهذا من ضمن ما يميز nodejs عن غيرها.

مثال على استخدام دالة pipe لارسال ملف html إلى المتصفح في nodejs:

const fs = require("fs");
const http = require("http");

http.createServer((req, res) => {
    let stream = fs.createReadStream("index.html");
    res.writeHead(200, {
        "Content-Type": "text/html; charset=utf8"
    })
    stream.pipe(res);
}).listen(3000);

لمعرفة تفاصيل أكثر يمكنك قراءة الدرس التالي: