Menu

fs.readFile في Node.js: قراءة الملفات بكل الطرق

اقرأ ملفًا في Node.js عبر fs.readFile (مع callback) أو fs.readFileSync أو await readFile من fs/promises. مرّر 'utf8' لتحصل على نص، وتعامل مع ENOENT حين يكون الملف غير موجود.

تحتوي هذه الصفحة على محررات قابلة للتشغيل. حرّر، شغّل، وشاهد النتيجة فوراً.

تقرأ fs.readFile(path, 'utf8', callback) ملفًا كاملًا وتمرر محتواه إلى دالة callback كنص. وتعيد fs.readFileSync(path, 'utf8') النص مباشرة بعد أن تنتظر انتهاء القراءة، بينما تفعل await readFile(path, 'utf8') من fs/promises الشيء نفسه دون حجب. إذا حذفت 'utf8' تحصل على Buffer من البايتات الخام بدلًا من النص.

يُطبع readFile called أولًا: readFile تبدأ القراءة فقط، والـ callback يعمل حين يجهز المحتوى. احذف 'utf8', وشغّل من جديد: يستقبل الـ callback القيمة <Buffer 42 75 79 20 6d 69 6c 6b 0a 43 61 6c 6c 20 41 64 61>، وهي البايتات الخام للملف.

readFile مقابل readFileSync مقابل fs/promises

الثلاثة تقرأ الملف نفسه. الفرق في طريقة حصولك على النتيجة، وفي ما إذا كان بقية البرنامج ينتظر.

يُطبع السطر المتزامن أولًا لأن لا شيء آخر يعمل حتى يعود. ينتهي الآخران بعد الشيفرة الرئيسية، بحسب الترتيب الذي تكتمل به قراءتهما.

readFileSyncreadFile (callback)readFile من fs/promises
تعيدالمحتوىundefinedوعدًا بالمحتوى
تحجب البرنامجنعملالا
الأخطاءتُرمى، استخدم try/catchأول وسيط في الـ callbackوعد مرفوض، try/catch مع await
استخدمها فيشيفرة بدء التشغيل والسكربتاتشيفرة callback القديمةالشيفرة الجديدة

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

التعامل مع ملف غير موجود (ENOENT)

حين لا يكون الملف موجودًا، يحمل الخطأ code: 'ENOENT' ("error, no entry"). افحص err.code لتميّز الملف الغائب عن الأخطاء الأخرى، مثل مشكلة في الصلاحيات.

لا يجد الاستدعاء الأول الملف فيرجع إلى default settings؛ ويقرأ الثاني dark mode. إعادة رمي الأخطاء الأخرى تُبقي المشاكل الحقيقية ظاهرة بدلًا من استخدام القيم الافتراضية بصمت.

fs.existsSync: لماذا تكفي محاولة القراءة

تعيد fs.existsSync(path) القيمة true أو false، ومن المغري أن تتحقق قبل القراءة:

if (fs.existsSync('data.txt')) {
    const text = fs.readFileSync('data.txt', 'utf8');
}

هاتان خطوتان حيث تكفي واحدة، وقد يُحذف الملف بينهما فترمي القراءة خطأ رغم ذلك. جرّب القراءة وتعامل مع ENOENT، كما في المثال السابق. تناسب existsSync الحالات التي تحتاج فيها فقط إلى معرفة وجود شيء ولن تفتحه، مثل أن تقرر هل تنشئ مجلدًا.

قراءة ملف JSON

اقرأ النص، ثم حلّله بـ JSON.parse. الملف الذي فيه خطأ في الصياغة يرمي SyntaxError، فأبقِه داخل try نفسها.

يطبع 3001 وboolean: بعد التحليل تأخذ القيم أنواعها في JSON. تعمل require('./config.json') أيضًا، لكنها تخزّن النتيجة، فيعيد require الثاني الكائن القديم حتى بعد تغيّر الملف.

قراءة ملف سطرًا سطرًا

للملف الذي يتسع في الذاكرة، اقرأه كاملًا وقسّمه عند محرف السطر الجديد. وصفِّ النص الفارغ الذي يتركه السطر الجديد الأخير.

يعطي التقسيم 4 عناصر، آخرها فارغ، فتطبع الحلقة ثلاثة أسطر مرقّمة. الملفات المكتوبة على Windows تنهي أسطرها بـ \r\n؛ قسّم على /\r?\n/ لتتعامل مع الحالتين.

سجل بحجم عدة غيغابايتات لا يتسع في الذاكرة. اقرأه كتدفق (stream) بدلًا من ذلك، فلا يُحفظ إلا سطر واحد في كل مرة:

const fs = require('fs');
const readline = require('readline');

async function main() {
    const rl = readline.createInterface({
        input: fs.createReadStream('big.log'),
        crlfDelay: Infinity,
    });
    for await (const line of rl) {
        console.log(line);
    }
}
main();

أخطاء شائعة

استخدام النتيجة خارج الـ callback. const text = fs.readFile(...) قيمته undefined. لا يوجد المحتوى إلا داخل الـ callback، أو بعد await.

نسيان الترميز. دون 'utf8' تحصل على Buffer، فترمي data.split('\n') الخطأ data.split is not a function. مرّر الترميز كلما أردت نصًا.

مسارات نسبية إلى المجلد الخطأ. يُبحث عن 'data.txt' حيث شُغّل node. استخدم path.join(__dirname, 'data.txt') لملف يأتي بجوار سكربتك.

الأسئلة الشائعة

لماذا تعيد fs.readFile القيمة undefined؟

fs.readFile لا تعيد المحتوى. تبدأ القراءة وتستدعي دالة callback لاحقًا مع (err, data). استخدم البيانات داخل الـ callback، أو استدعِ readFileSync، أو انتظر نسخة الوعد بـ await.

أين يبحث Node عن مسار نسبي مثل 'data.txt'؟

في مجلد العمل الحالي، أي المجلد الذي شغّلت منه node، لا في مجلد السكربت. لقراءة ملف بجوار السكربت، ابنِ المسار بـ path.join(__dirname, 'data.txt').

هل تستطيع fs.readFile قراءة ملف من عنوان URL؟

لا، فهي تقرأ من نظام الملفات فقط. للحصول على ملف عبر HTTP، استخدم fetch ثم await res.text().

ما أكبر ملف تستطيع readFile التعامل معه؟

تحمّل الملف كاملًا في الذاكرة، لذا فهي مناسبة لملفات الإعدادات والقوالب وملفات البيانات الصغيرة. أما الملفات التي تبلغ مئات الميغابايتات فاقرأها على أجزاء عبر fs.createReadStream.

رسم توضيحي للغات البرمجة في Coddy

تعلّم البرمجة مع Coddy

ابدأ الآن